Compare commits
7 Commits
867686e409
...
9db080dc0f
| Author | SHA1 | Date |
|---|---|---|
|
|
9db080dc0f | |
|
|
b1bdb3c540 | |
|
|
766cfc0f8f | |
|
|
890cb8819b | |
|
|
47b94056ac | |
|
|
96610b7ed0 | |
|
|
00b178103e |
112
nvim/init.lua
112
nvim/init.lua
|
|
@ -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,11 +93,22 @@ 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 })
|
||||
vim.keymap.set("n", "s", ":DBUIToggle<CR>", { silent = true })
|
||||
vim.keymap.set("n", "x", "<Plug>(DBUI_ExecuteQuery)", { remap = true })
|
||||
vim.keymap.set("n", "q", function()
|
||||
local ok = pcall(vim.cmd, "wq")
|
||||
if not ok then vim.cmd("q") end
|
||||
|
|
@ -145,3 +157,101 @@ 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 floating windows (sideward T: left column overlay) ───────────────────
|
||||
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
|
||||
|
||||
local function _pim_float(row, col, height, width, border)
|
||||
local buf = vim.api.nvim_create_buf(false, true)
|
||||
local win = vim.api.nvim_open_win(buf, true, {
|
||||
relative = "editor",
|
||||
row = row,
|
||||
col = col,
|
||||
height = math.max(1, height),
|
||||
width = math.max(1, width),
|
||||
style = "minimal",
|
||||
border = border or "none",
|
||||
zindex = 50,
|
||||
})
|
||||
vim.api.nvim_set_option_value("winhighlight", "Normal:Normal,NormalNC:Normal", { win = win })
|
||||
return win
|
||||
end
|
||||
|
||||
-- n/g/f: individual centered floating windows
|
||||
local _solo = {}
|
||||
|
||||
local function toggle_solo(key, cmd, label)
|
||||
local win = _solo[key]
|
||||
if win and vim.api.nvim_win_is_valid(win) then
|
||||
_pim_close_win(win)
|
||||
_solo[key] = nil
|
||||
return
|
||||
end
|
||||
local H = vim.o.lines - 2
|
||||
local W = vim.o.columns
|
||||
local h = math.max(1, math.floor(H * 0.85))
|
||||
local w = math.max(1, math.floor(W * 0.85))
|
||||
-- centre accounting for the 1-cell rounded border on each side
|
||||
local r = math.max(0, math.floor((H - h - 2) / 2))
|
||||
local c = math.max(0, math.floor((W - w - 2) / 2))
|
||||
local win_id = _pim_float(r, c, h, w, "rounded")
|
||||
local ok, err = pcall(vim.cmd, cmd)
|
||||
if not ok then _pim_scratch(label, err) end
|
||||
_solo[key] = win_id
|
||||
end
|
||||
|
||||
vim.keymap.set("n", "n", function() toggle_solo("n", "terminal alot", "alot") end, { silent = true })
|
||||
vim.keymap.set("n", "g", function() toggle_solo("g", "Calendar -position=here", "calendar.vim") end, { silent = true })
|
||||
vim.keymap.set("n", "f", function() toggle_solo("f", "terminal abook", "abook") end, { silent = true })
|
||||
|
||||
-- r: sideward-T overlay — left column (bar of the T) with three stacked panes,
|
||||
-- document remains visible to the right (the stem of the T)
|
||||
local _pim_wins = {}
|
||||
|
||||
local function toggle_pim()
|
||||
if #_pim_wins > 0 and vim.api.nvim_win_is_valid(_pim_wins[1]) then
|
||||
for _, w in ipairs(_pim_wins) do _pim_close_win(w) end
|
||||
_pim_wins = {}
|
||||
return
|
||||
end
|
||||
|
||||
local H = vim.o.lines - 2
|
||||
local col_w = math.min(vim.o.columns, math.max(90, math.floor(vim.o.columns * 0.45)))
|
||||
|
||||
-- abook gets a fixed 24-line minimum; mail/calendar split the rest 57/43
|
||||
local ab_h = math.max(24, math.floor(H * 0.30))
|
||||
local rest = math.max(2, H - ab_h)
|
||||
local mail_h = math.max(1, math.floor(rest * 0.57))
|
||||
local cal_h = math.max(1, rest - mail_h)
|
||||
|
||||
local w1 = _pim_float(0, 0, mail_h, col_w)
|
||||
local ok, err = pcall(vim.cmd, "terminal alot")
|
||||
if not ok then _pim_scratch("alot", err) end
|
||||
|
||||
local w2 = _pim_float(mail_h, 0, cal_h, col_w)
|
||||
ok, err = pcall(vim.cmd, "Calendar -position=here")
|
||||
if not ok then _pim_scratch("calendar.vim", err) end
|
||||
|
||||
local w3 = _pim_float(mail_h + cal_h, 0, ab_h, col_w)
|
||||
ok, err = pcall(vim.cmd, "terminal abook")
|
||||
if not ok then _pim_scratch("abook", err) end
|
||||
|
||||
_pim_wins = { w1, w2, w3 }
|
||||
vim.api.nvim_set_current_win(w1)
|
||||
end
|
||||
|
||||
vim.keymap.set("n", "x", toggle_pim, { silent = true })
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../../lib/logging.sh"
|
||||
|
||||
log "Installing mail stack (isync, msmtp, notmuch, alot)..."
|
||||
sudo pacman -S --noconfirm --needed isync msmtp notmuch alot
|
||||
|
||||
# ── Credentials ───────────────────────────────────────────────────────────────
|
||||
read -rp "Full name : " FULL_NAME
|
||||
read -rp "Email address : " EMAIL
|
||||
read -rp "IMAP host (e.g. mail.example.com) : " IMAP_HOST
|
||||
read -rp "IMAP port [993] : " IMAP_PORT; IMAP_PORT="${IMAP_PORT:-993}"
|
||||
read -rp "IMAP username [$EMAIL] : " IMAP_USER; IMAP_USER="${IMAP_USER:-$EMAIL}"
|
||||
read -rsp "IMAP password : " IMAP_PASS; echo
|
||||
read -rp "SMTP host (e.g. mail.example.com) : " SMTP_HOST
|
||||
read -rp "SMTP port [587] : " SMTP_PORT; SMTP_PORT="${SMTP_PORT:-587}"
|
||||
|
||||
MAILDIR="$HOME/Mail"
|
||||
mkdir -p "$MAILDIR"
|
||||
|
||||
# ── mbsync ────────────────────────────────────────────────────────────────────
|
||||
log "Writing ~/.mbsyncrc..."
|
||||
cat > ~/.mbsyncrc << EOF
|
||||
IMAPAccount main
|
||||
Host $IMAP_HOST
|
||||
Port $IMAP_PORT
|
||||
User $IMAP_USER
|
||||
Pass $IMAP_PASS
|
||||
SSLType IMAPS
|
||||
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
IMAPStore main-remote
|
||||
Account main
|
||||
|
||||
MaildirStore main-local
|
||||
SubFolders Verbatim
|
||||
Path $MAILDIR/
|
||||
Inbox $MAILDIR/INBOX
|
||||
|
||||
Channel main
|
||||
Far :main-remote:
|
||||
Near :main-local:
|
||||
Patterns *
|
||||
Create Both
|
||||
SyncState *
|
||||
Expunge Both
|
||||
EOF
|
||||
chmod 600 ~/.mbsyncrc
|
||||
|
||||
# ── msmtp ─────────────────────────────────────────────────────────────────────
|
||||
log "Writing ~/.msmtprc..."
|
||||
cat > ~/.msmtprc << EOF
|
||||
defaults
|
||||
tls on
|
||||
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||
logfile ~/.msmtp.log
|
||||
|
||||
account main
|
||||
host $SMTP_HOST
|
||||
port $SMTP_PORT
|
||||
auth on
|
||||
user $IMAP_USER
|
||||
password $IMAP_PASS
|
||||
from $EMAIL
|
||||
|
||||
account default : main
|
||||
EOF
|
||||
chmod 600 ~/.msmtprc
|
||||
|
||||
# ── notmuch ───────────────────────────────────────────────────────────────────
|
||||
log "Configuring notmuch..."
|
||||
notmuch config set user.name "$FULL_NAME"
|
||||
notmuch config set user.email "$EMAIL"
|
||||
notmuch config set database.path "$MAILDIR"
|
||||
notmuch config set maildir.synchronize_flags true
|
||||
notmuch config set new.tags "unread;inbox"
|
||||
|
||||
# post-new hook: tag sent mail, remove inbox from trash
|
||||
mkdir -p "$MAILDIR/.notmuch/hooks"
|
||||
cat > "$MAILDIR/.notmuch/hooks/post-new" << 'EOF'
|
||||
#!/bin/bash
|
||||
notmuch tag +sent -inbox -- folder:Sent
|
||||
notmuch tag +trash -inbox -unread -- folder:Trash
|
||||
notmuch tag +draft -inbox -- folder:Drafts
|
||||
notmuch tag +spam -inbox -unread -- folder:Spam folder:Junk
|
||||
EOF
|
||||
chmod +x "$MAILDIR/.notmuch/hooks/post-new"
|
||||
|
||||
# ── alot ──────────────────────────────────────────────────────────────────────
|
||||
log "Writing ~/.config/alot/config..."
|
||||
mkdir -p ~/.config/alot
|
||||
cat > ~/.config/alot/config << EOF
|
||||
[accounts]
|
||||
[[main]]
|
||||
realname = $FULL_NAME
|
||||
address = $EMAIL
|
||||
sendmail_command = msmtp -a main
|
||||
sent_box = maildir://$MAILDIR/Sent
|
||||
draft_box = maildir://$MAILDIR/Drafts
|
||||
EOF
|
||||
|
||||
# ── systemd timer for periodic sync ───────────────────────────────────────────
|
||||
log "Installing mbsync systemd user timer (every 5 min)..."
|
||||
mkdir -p ~/.config/systemd/user
|
||||
|
||||
cat > ~/.config/systemd/user/mbsync.service << EOF
|
||||
[Unit]
|
||||
Description=Sync mail with mbsync
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/mbsync -a
|
||||
ExecStartPost=/usr/bin/notmuch new
|
||||
EOF
|
||||
|
||||
cat > ~/.config/systemd/user/mbsync.timer << EOF
|
||||
[Unit]
|
||||
Description=Run mbsync every 5 minutes
|
||||
|
||||
[Timer]
|
||||
OnBootSec=2min
|
||||
OnUnitActiveSec=5min
|
||||
Unit=mbsync.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now mbsync.timer
|
||||
|
||||
# ── initial sync ──────────────────────────────────────────────────────────────
|
||||
log "Running initial mail sync..."
|
||||
mbsync -a
|
||||
notmuch new
|
||||
|
||||
log "Mail setup complete. Syncs automatically every 5 min via systemd timer."
|
||||
log "Open alot with: alot | Check timer: systemctl --user status mbsync.timer"
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue