feat(nvim): add PIM panel with calendar, alot mail, and abook

Adds itchyny/calendar.vim plugin and keybinds for a PIM sidebar:
- r: full-screen tab with alot (top), calendar + abook (bottom split)
- n/g/f: individual vsplit toggles for alot, calendar, abook
- Restores <C-hjkl> window nav inside calendar buffers
- shell-setup.sh installs notmuch, alot, abook (AUR) and syncs lazy.nvim

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
Amir Alexander Abdelbaki 2026-05-26 11:52:05 +02:00
parent 867686e409
commit 00b178103e
2 changed files with 102 additions and 1 deletions

View File

@ -37,6 +37,7 @@ require("lazy").setup({
"nvim-mini/mini.icons",
"tadmccorkle/markdown.nvim",
{ "ellisonleao/glow.nvim", config = true },
"itchyny/calendar.vim",
{
"greggh/claude-code.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
@ -92,6 +93,18 @@ vim.keymap.set("n", "<C-h>", "<C-w>h")
vim.keymap.set("n", "<C-j>", "<C-w>j")
vim.keymap.set("n", "<C-k>", "<C-w>k")
-- calendar.vim steals <C-hjkl> for month nav; restore window movement
vim.api.nvim_create_autocmd("FileType", {
pattern = "calendar",
callback = function()
local o = { buffer = true, silent = true }
vim.keymap.set("n", "<C-l>", "<C-w>w", o)
vim.keymap.set("n", "<C-h>", "<C-w>h", o)
vim.keymap.set("n", "<C-j>", "<C-w>j", o)
vim.keymap.set("n", "<C-k>", "<C-w>k", o)
end,
})
-- quick actions
vim.keymap.set("n", "t", ":FloatermNew<CR>", { silent = true })
vim.keymap.set("n", "e", ":NERDTreeToggle<CR><C-W>l", { silent = true })
@ -145,3 +158,80 @@ end, { expr = true, silent = true })
vim.keymap.set("i", "<CR>", function()
return vim.fn["coc#pum#visible"]() == 1 and vim.fn["coc#pum#confirm"]() or "<CR>"
end, { expr = true, silent = true })
-- ── PIM sidebar (calendar / notmuch / abook) ──────────────────────────────────
local function _pim_scratch(label, err)
vim.cmd("enew")
vim.bo.buftype = "nofile"
vim.bo.buflisted = false
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "[" .. label .. " unavailable]", "", err or "" })
end
local function _pim_close_win(win)
if not vim.api.nvim_win_is_valid(win) then return end
local buf = vim.api.nvim_win_get_buf(win)
vim.api.nvim_win_close(win, true)
if vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buftype == "terminal" then
pcall(vim.api.nvim_buf_delete, buf, { force = true })
end
end
-- individual toggles: n = notmuch/alot, g = calendar, f = find/abook
local _solo = {}
local function toggle_solo(key, cmd, label, width)
local win = _solo[key]
if win and vim.api.nvim_win_is_valid(win) then
_pim_close_win(win)
_solo[key] = nil
else
local prev = vim.api.nvim_get_current_win()
vim.cmd("topleft vsplit")
vim.api.nvim_win_set_width(0, width)
local ok, err = pcall(vim.cmd, cmd)
if not ok then _pim_scratch(label, err) end
_solo[key] = vim.api.nvim_get_current_win()
vim.api.nvim_set_current_win(prev)
end
end
vim.keymap.set("n", "n", function() toggle_solo("n", "terminal alot", "alot", 55) end, { silent = true })
vim.keymap.set("n", "g", function() toggle_solo("g", "Calendar", "calendar.vim", 35) end, { silent = true })
vim.keymap.set("n", "f", function() toggle_solo("f", "terminal abook", "abook", 80) end, { silent = true })
-- r = full-screen PIM tab (mail top, calendar bottom-left, abook bottom-right)
local _pim_tab = nil
local function toggle_pim()
if _pim_tab and vim.api.nvim_tabpage_is_valid(_pim_tab) then
vim.cmd("tabclose " .. vim.api.nvim_tabpage_get_number(_pim_tab))
_pim_tab = nil
return
end
vim.cmd("tabnew")
_pim_tab = vim.api.nvim_get_current_tabpage()
-- top pane: alot (mail), full width
local ok, err = pcall(vim.cmd, "terminal alot")
if not ok then _pim_scratch("alot", err) end
-- split bottom third for calendar + abook
vim.cmd("belowright split")
vim.cmd("resize 24")
-- bottom-left: calendar
vim.cmd("leftabove vsplit")
ok, err = pcall(vim.cmd, "Calendar")
if not ok then _pim_scratch("calendar.vim", err) end
-- bottom-right: abook
vim.cmd("wincmd l")
ok, err = pcall(vim.cmd, "terminal abook")
if not ok then _pim_scratch("abook", err) end
-- focus mail
vim.cmd("wincmd k")
end
vim.keymap.set("n", "r", toggle_pim, { silent = true })

View File

@ -6,7 +6,7 @@ log "Updating system..."
sudo pacman -Syu --noconfirm
log "Installing base shell packages..."
PACKAGES=(zsh neovim curl pyright bash atftp bash-language-server btop clang fastfetch fzf hyfetch lua-language-server micro nano pulsemixer yazi z qrencode distrobox dysk python python-pip glow)
PACKAGES=(zsh neovim curl pyright bash atftp bash-language-server btop clang fastfetch fzf hyfetch lua-language-server micro nano pulsemixer yazi z qrencode distrobox dysk python python-pip glow notmuch alot)
for pkg in "${PACKAGES[@]}"; do
if ! pacman -Qi "$pkg" &>/dev/null; then
log "Installing $pkg..."
@ -16,6 +16,14 @@ for pkg in "${PACKAGES[@]}"; do
fi
done
# abook (AUR)
if ! command -v abook &>/dev/null; then
log "Installing abook (AUR)..."
yay -S --noconfirm --needed abook
else
skip "abook already installed."
fi
# yay
if ! command -v yay &>/dev/null; then
log "Installing yay..."
@ -64,6 +72,9 @@ cp -r ~/Dotfiles/micro ~/.config/
rm -rf ~/.config/nvim
ln -sf ~/Dotfiles/nvim ~/.config/nvim
log "Syncing neovim plugins (lazy.nvim)..."
nvim --headless "+Lazy! sync" +qa 2>/dev/null || true
rm -rf ~/.config/yazi
ln -sf ~/Dotfiles/yazi ~/.config/yazi