Compare commits
3 commits
54be488d73
...
4f39c80e25
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f39c80e25 | |||
| a88fde31cb | |||
| 9e8182da6a |
45 changed files with 1462 additions and 797 deletions
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[bin/*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
keys:
|
keys:
|
||||||
- &pickwick age13cfe8fhp4m978qlcur46vkkxepsl93ggwe53kmhue9xtpgr5zu5q4y6ln2
|
- &pickwick age13cfe8fhp4m978qlcur46vkkxepsl93ggwe53kmhue9xtpgr5zu5q4y6ln2
|
||||||
- &lemur age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6
|
- &lemur age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6
|
||||||
|
- &dango age15vscvpe79l287h8f3hssrj2r45xy0l3ns94zfue2fxlq43cqdsxq58vq3c
|
||||||
creation_rules:
|
creation_rules:
|
||||||
|
- path_regex: secrets/wb\.txt$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *pickwick
|
||||||
|
- *lemur
|
||||||
|
- *dango
|
||||||
- path_regex: home/email/secrets.yaml$
|
- path_regex: home/email/secrets.yaml$
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *pickwick
|
- *pickwick
|
||||||
- *lemur
|
- *lemur
|
||||||
|
- *dango
|
||||||
|
|
|
||||||
5
bin/b
5
bin/b
|
|
@ -10,9 +10,8 @@ title=${2:-}
|
||||||
|
|
||||||
global="$HOME/Personal/bookmarks.txt"
|
global="$HOME/Personal/bookmarks.txt"
|
||||||
|
|
||||||
if [ -n "$url" ]
|
if [ -n "$url" ]; then
|
||||||
then
|
echo "$url $title" >>$global
|
||||||
echo "$url $title" >> $global
|
|
||||||
else
|
else
|
||||||
local="$PWD/bookmarks.txt"
|
local="$PWD/bookmarks.txt"
|
||||||
|
|
||||||
|
|
|
||||||
22
bin/cb
22
bin/cb
|
|
@ -19,19 +19,17 @@ WSL_paste() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CYGWIN_copy() {
|
CYGWIN_copy() {
|
||||||
cat > /dev/clipboard
|
cat >/dev/clipboard
|
||||||
}
|
}
|
||||||
|
|
||||||
CYGWIN_paste() {
|
CYGWIN_paste() {
|
||||||
cat /dev/clipboard
|
cat /dev/clipboard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MAC_copy() {
|
MAC_copy() {
|
||||||
cat | pbcopy
|
cat | pbcopy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MAC_paste() {
|
MAC_paste() {
|
||||||
pbpaste
|
pbpaste
|
||||||
}
|
}
|
||||||
|
|
@ -85,20 +83,20 @@ detect_os() {
|
||||||
printf WSL
|
printf WSL
|
||||||
else
|
else
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
Linux*) printf LINUX;;
|
Linux*) printf LINUX ;;
|
||||||
Darwin*) printf MAC;;
|
Darwin*) printf MAC ;;
|
||||||
CYGWIN*) printf CYGWIN;;
|
CYGWIN*) printf CYGWIN ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function debug() {
|
function debug() {
|
||||||
stdin_is_a_pipe && echo "stdin_is_a_pipe: 1" >> /tmp/ono || echo "stdin_is_a_pipe: 0" >> /tmp/ono
|
stdin_is_a_pipe && echo "stdin_is_a_pipe: 1" >>/tmp/ono || echo "stdin_is_a_pipe: 0" >>/tmp/ono
|
||||||
stdin_is_a_tty && echo "stdin_is_a_tty: 1" >> /tmp/ono || echo "stdin_is_a_tty: 0" >> /tmp/ono
|
stdin_is_a_tty && echo "stdin_is_a_tty: 1" >>/tmp/ono || echo "stdin_is_a_tty: 0" >>/tmp/ono
|
||||||
stdin_is_pipe_like && echo "stdin_is_pipe_like: 1" >> /tmp/ono || echo "stdin_is_pipe_like: 0" >> /tmp/ono
|
stdin_is_pipe_like && echo "stdin_is_pipe_like: 1" >>/tmp/ono || echo "stdin_is_pipe_like: 0" >>/tmp/ono
|
||||||
stdout_is_pipe_like && echo "stdout_is_pipe_like: 1" >> /tmp/ono || echo "stdout_is_pipe_like: 0" >> /tmp/ono
|
stdout_is_pipe_like && echo "stdout_is_pipe_like: 1" >>/tmp/ono || echo "stdout_is_pipe_like: 0" >>/tmp/ono
|
||||||
stdout_is_a_tty && echo "stdout_is_a_tty: 1" >> /tmp/ono || echo "stdout_is_a_tty: 0" >> /tmp/ono
|
stdout_is_a_tty && echo "stdout_is_a_tty: 1" >>/tmp/ono || echo "stdout_is_a_tty: 0" >>/tmp/ono
|
||||||
echo >> /tmp/ono
|
echo >>/tmp/ono
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,5 @@ if [ $# == 1 ]; then
|
||||||
sleepsec=$1
|
sleepsec=$1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
sleep $sleepsec
|
sleep $sleepsec
|
||||||
pbcopy < /dev/null
|
pbcopy </dev/null
|
||||||
|
|
||||||
|
|
|
||||||
31
bin/git-apply-patch
Executable file
31
bin/git-apply-patch
Executable file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Interactive git patch applier - finds git repos and applies patch from stdin
|
||||||
|
|
||||||
|
# Save stdin (the patch) to a temp file
|
||||||
|
patch_file=$(mktemp /tmp/patch.XXXXXX)
|
||||||
|
cat >"$patch_file"
|
||||||
|
|
||||||
|
# Find git repos and select with fzf
|
||||||
|
repo=$(find ~/projects ~/code ~/dotfiles ~ -maxdepth 3 -type d -name ".git" 2>/dev/null |
|
||||||
|
sed 's/\/.git$//' |
|
||||||
|
sort -u |
|
||||||
|
fzf --prompt="Select repo to apply patch: " --height=40% --reverse)
|
||||||
|
|
||||||
|
if [ -z "$repo" ]; then
|
||||||
|
echo "No repo selected, patch saved to: $patch_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$repo" || exit 1
|
||||||
|
echo "Applying patch to: $repo"
|
||||||
|
git apply "$patch_file"
|
||||||
|
status=$?
|
||||||
|
|
||||||
|
if [ $status -eq 0 ]; then
|
||||||
|
echo "Patch applied successfully!"
|
||||||
|
rm "$patch_file"
|
||||||
|
else
|
||||||
|
echo "Failed to apply patch. Patch saved to: $patch_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $status
|
||||||
|
|
@ -11,42 +11,42 @@ presentation_left_gaps=80
|
||||||
presentation_right_gaps=80
|
presentation_right_gaps=80
|
||||||
|
|
||||||
if [ "$1" == "on" ]; then
|
if [ "$1" == "on" ]; then
|
||||||
# Save original lines with line numbers
|
# Save original lines with line numbers
|
||||||
grep -n 'outer\.top\|outer\.bottom\|outer\.left\|outer\.right' "$CONFIG_FILE" > "$BACKUP_FILE"
|
grep -n 'outer\.top\|outer\.bottom\|outer\.left\|outer\.right' "$CONFIG_FILE" >"$BACKUP_FILE"
|
||||||
|
|
||||||
# Replace with presentation values
|
# Replace with presentation values
|
||||||
sed -i'' -e "s/^\([[:space:]]*outer\.top[[:space:]]*=\).*/\1 ${presentation_top_gaps}/" "$CONFIG_FILE"
|
sed -i'' -e "s/^\([[:space:]]*outer\.top[[:space:]]*=\).*/\1 ${presentation_top_gaps}/" "$CONFIG_FILE"
|
||||||
sed -i'' -e "s/^\([[:space:]]*outer\.bottom[[:space:]]*=\).*/\1 ${presentation_bottom_gaps}/" "$CONFIG_FILE"
|
sed -i'' -e "s/^\([[:space:]]*outer\.bottom[[:space:]]*=\).*/\1 ${presentation_bottom_gaps}/" "$CONFIG_FILE"
|
||||||
sed -i'' -e "s/^\([[:space:]]*outer\.left[[:space:]]*=\).*/\1 ${presentation_left_gaps}/" "$CONFIG_FILE"
|
sed -i'' -e "s/^\([[:space:]]*outer\.left[[:space:]]*=\).*/\1 ${presentation_left_gaps}/" "$CONFIG_FILE"
|
||||||
sed -i'' -e "s/^\([[:space:]]*outer\.right[[:space:]]*=\).*/\1 ${presentation_right_gaps}/" "$CONFIG_FILE"
|
sed -i'' -e "s/^\([[:space:]]*outer\.right[[:space:]]*=\).*/\1 ${presentation_right_gaps}/" "$CONFIG_FILE"
|
||||||
|
|
||||||
# Set dark wallpaper for presentation
|
# Set dark wallpaper for presentation
|
||||||
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/black-gray.jpg"' > /dev/null 2>&1
|
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/black-gray.jpg"' >/dev/null 2>&1
|
||||||
|
|
||||||
aerospace reload-config
|
aerospace reload-config
|
||||||
echo -n "Presentation mode ON"
|
echo -n "Presentation mode ON"
|
||||||
|
|
||||||
elif [ "$1" == "off" ]; then
|
elif [ "$1" == "off" ]; then
|
||||||
if [ ! -f "$BACKUP_FILE" ]; then
|
if [ ! -f "$BACKUP_FILE" ]; then
|
||||||
echo "Error: No backup found. Run 'presentation-mode on' first."
|
echo "Error: No backup found. Run 'presentation-mode on' first."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Restore original values line by line
|
# Restore original values line by line
|
||||||
while IFS=: read -r line_num content; do
|
while IFS=: read -r line_num content; do
|
||||||
# Escape special characters for sed
|
# Escape special characters for sed
|
||||||
escaped_content=$(printf '%s\n' "$content" | sed 's/[&/\]/\\&/g')
|
escaped_content=$(printf '%s\n' "$content" | sed 's/[&/\]/\\&/g')
|
||||||
sed -i'' -e "${line_num}s/.*/${escaped_content}/" "$CONFIG_FILE"
|
sed -i'' -e "${line_num}s/.*/${escaped_content}/" "$CONFIG_FILE"
|
||||||
done < "$BACKUP_FILE"
|
done <"$BACKUP_FILE"
|
||||||
|
|
||||||
# Restore original wallpaper
|
# Restore original wallpaper
|
||||||
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/bluering.png"' > /dev/null 2>&1
|
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/bluering.png"' >/dev/null 2>&1
|
||||||
|
|
||||||
rm "$BACKUP_FILE"
|
rm "$BACKUP_FILE"
|
||||||
aerospace reload-config
|
aerospace reload-config
|
||||||
echo "Presentation mode OFF"
|
echo "Presentation mode OFF"
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "Usage: presentation-mode [on|off]"
|
echo "Usage: presentation-mode [on|off]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
336
bin/wb
Executable file
336
bin/wb
Executable file
|
|
@ -0,0 +1,336 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
thisFile=$(realpath "$0")
|
||||||
|
DOTFILES="${DOTFILES:-$HOME/dotfiles}"
|
||||||
|
BOOKMARKS_FILE="${DOTFILES}/secrets/wb.txt"
|
||||||
|
|
||||||
|
# Decrypt bookmarks from sops
|
||||||
|
getBookmarks() {
|
||||||
|
if [[ -f "${BOOKMARKS_FILE}" ]]; then
|
||||||
|
# Unencrypted file (for development/testing)
|
||||||
|
cat "${BOOKMARKS_FILE}"
|
||||||
|
elif [[ -f "${BOOKMARKS_FILE%.txt}.enc" ]]; then
|
||||||
|
# Encrypted file
|
||||||
|
sops --decrypt --input-type binary "${BOOKMARKS_FILE%.txt}.enc" 2>/dev/null
|
||||||
|
else
|
||||||
|
echo "Error: No bookmarks file found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Defaults
|
||||||
|
isCopy=0
|
||||||
|
editMode=0
|
||||||
|
q=""
|
||||||
|
noFuzzy=0
|
||||||
|
queryMode=0
|
||||||
|
|
||||||
|
if ! type fzf >/dev/null 2>&1; then
|
||||||
|
noFuzzy=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f /tmp/.wb
|
||||||
|
clear-pbcopy 60 &
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
bks() {
|
||||||
|
getBookmarks | awk '!/^[[:space:]]*#/ && !/^[[:space:]]*$/ {print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# If key == $q, then it's a match, then we do the following:
|
||||||
|
# a. Copy the "url" to the clipboard (with "pbcopy" in Mac or
|
||||||
|
# "clip" in Linux). How do we know it's a Mac, we just simply
|
||||||
|
# check if there's a ~/Music folder in your homedir. If
|
||||||
|
# there is, it's likely a Mac, else it's Linux.
|
||||||
|
# b. I have a "clear-pbcopy" script that basically clears the
|
||||||
|
# clipboard after 20 seconds (for security reason) because
|
||||||
|
# you don't want to accidentally copy-paste your personal
|
||||||
|
# links in your email or your chat applications. It is as simple as
|
||||||
|
# a oneline command:
|
||||||
|
# "sleep 20; echo "nothing-here" | pbcopy"
|
||||||
|
# c. If the first argument is "-c" then we mean we just want to
|
||||||
|
# copy the string to the clipboard, so we just continue
|
||||||
|
# d. Then we see if the "url" contains "http" or "www", if so
|
||||||
|
# we open it with ~/bin/browser. You must have your own
|
||||||
|
# "browser" script that opens your favorite web browser, e.g.
|
||||||
|
# in Mac, my "~/bin/browser" contains:
|
||||||
|
# open -a /Applications/Firefox.app $*
|
||||||
|
# However, if the "url" does not contain http/www,
|
||||||
|
# e.g. the key and url line is like this:
|
||||||
|
# mytodofile ~/Documents/mytodofile.txt
|
||||||
|
# then I open it "open" command line provided by Mac
|
||||||
|
# d. We are done (exiting)
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ---------------------- a
|
||||||
|
echo " copying $url"
|
||||||
|
echo "$url" | cb
|
||||||
|
|
||||||
|
# ---------------------- b
|
||||||
|
if type clear-pbcopy >/dev/null 2>&1; then
|
||||||
|
clear-pbcopy 60 &
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------- c
|
||||||
|
if [ $isCopy == 1 ]; then
|
||||||
|
echo " Copied to clipboard"
|
||||||
|
echo ""
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------- d
|
||||||
|
echo " open $url"
|
||||||
|
x-open $url
|
||||||
|
|
||||||
|
# ---------------------- d
|
||||||
|
echo ""
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzzy() {
|
||||||
|
# Use awk to parse bookmarks in a single pass (much faster than bash loop)
|
||||||
|
formatted=$(getBookmarks | awk '
|
||||||
|
# Skip decorative headers and section dividers
|
||||||
|
/^#[-=~# ]*$/ || /^# *--/ || /^##+/ { next }
|
||||||
|
|
||||||
|
# Accumulate description and extract tags from comments
|
||||||
|
/^#[^#]/ {
|
||||||
|
sub(/^# */, "")
|
||||||
|
desc = desc (desc ? " " : "") $0
|
||||||
|
# Extract @tags
|
||||||
|
n = split($0, words, " ")
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if (words[i] ~ /^@/) {
|
||||||
|
tags = tags (tags ? " " : "") words[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle bookmark lines (non-comment, non-empty)
|
||||||
|
/^[^#[:space:]]/ {
|
||||||
|
key = $1
|
||||||
|
# Skip @-prefixed keys
|
||||||
|
if (key ~ /^@/) { desc = ""; tags = ""; next }
|
||||||
|
|
||||||
|
# Get URL (everything after first field)
|
||||||
|
url = $0
|
||||||
|
sub(/^[^ \t]+[ \t]+/, "", url)
|
||||||
|
|
||||||
|
# Clean description
|
||||||
|
gsub(/\n/, " ", desc)
|
||||||
|
if (desc == "") desc = "-"
|
||||||
|
if (tags == "") tags = "-"
|
||||||
|
|
||||||
|
print key "\t" url "\t" desc "\t" tags
|
||||||
|
|
||||||
|
desc = ""
|
||||||
|
tags = ""
|
||||||
|
}
|
||||||
|
')
|
||||||
|
|
||||||
|
selected_line=$(echo "$formatted" |
|
||||||
|
fzf -i --with-nth=1 \
|
||||||
|
--delimiter=$'\t' \
|
||||||
|
--query="$q" \
|
||||||
|
--prompt="🔍 Select bookmark: " \
|
||||||
|
--preview='bash -c "url=\$(echo {} | cut -f2); desc=\$(echo {} | cut -f3); tags=\$(echo {} | cut -f4); echo -e \"\$url\n\nDesc: \$desc\n\nTags: \$tags\""' \
|
||||||
|
--preview-window=down:12:wrap)
|
||||||
|
|
||||||
|
if [[ -n "$selected_line" ]]; then
|
||||||
|
IFS=$'\t' read -r key url _ <<<"$selected_line"
|
||||||
|
execute "$url"
|
||||||
|
else
|
||||||
|
echo " No selection made"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
help() {
|
||||||
|
echo ""
|
||||||
|
echo "Usage: wb [-c] [-e] <key> [key2] [key3] ..."
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -c Copy to clipboard without opening"
|
||||||
|
echo " -e Edit the bookmarks file"
|
||||||
|
echo " -nf No Fuzzy Match"
|
||||||
|
echo " -h Show help"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " wb cnn # Open the cnn bookmark"
|
||||||
|
echo " wb -c gmail # Copy Gmail URL without opening"
|
||||||
|
echo " wb 230 zoom # Open bookmark matching '230.*zoom'"
|
||||||
|
echo " wb ai sci zoom # Open bookmark matching 'ai.*sci.*zoom'"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# [ 70-char wide ]
|
||||||
|
# 34567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
# 1 2 3 4 5 6 7
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# 0. Setup $thisFile and
|
||||||
|
# if "wb" is called with no arguments, then
|
||||||
|
# just open this "wb" file with "e" --> emacs
|
||||||
|
# You can change "e" to "vi" or other text editor
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
args=()
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-c)
|
||||||
|
isCopy=1
|
||||||
|
;;
|
||||||
|
-e)
|
||||||
|
editMode=1
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-nf)
|
||||||
|
noFuzzy=1
|
||||||
|
;;
|
||||||
|
-q)
|
||||||
|
queryMode=1
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
args+=("$1")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build pattern from multiple arguments (e.g., "wb 230 si te" -> "230.*si.*te")
|
||||||
|
if [ ${#args[@]} -gt 0 ]; then
|
||||||
|
q="${args[0]}"
|
||||||
|
for ((i = 1; i < ${#args[@]}; i++)); do
|
||||||
|
q="$q.*${args[$i]}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $editMode == 1 ]]; then
|
||||||
|
encFile="${BOOKMARKS_FILE%.txt}.enc"
|
||||||
|
if [[ -f "$encFile" ]]; then
|
||||||
|
echo "Editing encrypted bookmarks file"
|
||||||
|
# Decrypt to the .txt file (matches .sops.yaml path_regex), edit, re-encrypt
|
||||||
|
trap "rm -f '${BOOKMARKS_FILE}'" EXIT
|
||||||
|
sops --decrypt --input-type binary --output-type binary "$encFile" >"${BOOKMARKS_FILE}"
|
||||||
|
${EDITOR:-vim} "${BOOKMARKS_FILE}"
|
||||||
|
sops --encrypt --input-type binary --output-type binary "${BOOKMARKS_FILE}" >"$encFile"
|
||||||
|
rm -f "${BOOKMARKS_FILE}"
|
||||||
|
echo "Saved and re-encrypted"
|
||||||
|
elif [[ -f "${BOOKMARKS_FILE}" ]]; then
|
||||||
|
echo "Editing ${BOOKMARKS_FILE}"
|
||||||
|
${EDITOR:-vim} "${BOOKMARKS_FILE}"
|
||||||
|
else
|
||||||
|
echo "Error: No bookmarks file found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $queryMode == 1 ]]; then
|
||||||
|
if [[ -z "$q" ]]; then
|
||||||
|
bs=$(bks)
|
||||||
|
else
|
||||||
|
bs=$(bks | grep -i "$q")
|
||||||
|
fi
|
||||||
|
num=$(echo "$bs" | wc -l | tr -d ' ')
|
||||||
|
bs=$(echo "$bs" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')
|
||||||
|
echo "$num bookmarks: ($bs)"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $q == "" ]]; then
|
||||||
|
if [[ $noFuzzy == 1 ]]; then
|
||||||
|
help
|
||||||
|
else
|
||||||
|
fuzzy
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
## 1. Find all bookmarks matching the pattern using regex
|
||||||
|
## Store matches in /tmp/.wb (using awk for speed)
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
tempFile=/tmp/.wb
|
||||||
|
getBookmarks | awk -v pattern="$q" '
|
||||||
|
!/^[[:space:]]*#/ && !/^[[:space:]]*$/ && $1 ~ pattern {print}
|
||||||
|
' >"$tempFile"
|
||||||
|
hitCount=$(wc -l <"$tempFile" | tr -d ' ')
|
||||||
|
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
## 2. Handle results based on hit count
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
|
||||||
|
# No hits found
|
||||||
|
if [ $hitCount -eq 0 ]; then
|
||||||
|
echo ""
|
||||||
|
if [[ $noFuzzy == 1 ]]; then
|
||||||
|
echo " '$q' not found"
|
||||||
|
echo " Available bookmarks matching pattern:"
|
||||||
|
bks | grep -iE "$q" | cat -n
|
||||||
|
else
|
||||||
|
fuzzy
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Multiple hits - check for exact match first
|
||||||
|
if [ $hitCount -gt 1 ]; then
|
||||||
|
exactHit=0
|
||||||
|
while read -r key url misc; do
|
||||||
|
if [[ "$key" == "$q" ]]; then
|
||||||
|
exactHit=1
|
||||||
|
echo "$key $url" >"$tempFile"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done <"$tempFile"
|
||||||
|
if [ $exactHit -eq 1 ]; then
|
||||||
|
hitCount=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Still multiple hits - show options or use fuzzy
|
||||||
|
if [ $hitCount -gt 1 ]; then
|
||||||
|
if [[ $noFuzzy == 1 ]]; then
|
||||||
|
echo ""
|
||||||
|
echo " Multiple matches for '$q':"
|
||||||
|
sort "$tempFile" | while read -r key url misc; do
|
||||||
|
echo " $key"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
fuzzy
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Single hit - execute
|
||||||
|
if [ $hitCount -eq 1 ]; then
|
||||||
|
read -r key url _ <"$tempFile"
|
||||||
|
execute "$url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
## 5. Bookmarks are now stored in secrets/wb.txt (or secrets/wb.enc when encrypted)
|
||||||
|
## To encrypt: sops --encrypt --input-type binary --output-type binary secrets/wb.txt > secrets/wb.enc
|
||||||
|
## Then remove secrets/wb.txt
|
||||||
|
## --------------------------------------------------------------------
|
||||||
|
|
@ -16,23 +16,23 @@ echo "Desired spaces: $DESIRED_SPACES"
|
||||||
yabai -m display --focus "$MAIN_DISPLAY"
|
yabai -m display --focus "$MAIN_DISPLAY"
|
||||||
|
|
||||||
if [ "$CURRENT_SPACE_COUNT" -lt "$DESIRED_SPACES" ]; then
|
if [ "$CURRENT_SPACE_COUNT" -lt "$DESIRED_SPACES" ]; then
|
||||||
MISSING_SPACES=$((DESIRED_SPACES - CURRENT_SPACE_COUNT))
|
MISSING_SPACES=$((DESIRED_SPACES - CURRENT_SPACE_COUNT))
|
||||||
echo "Creating $MISSING_SPACES spaces on display $MAIN_DISPLAY..."
|
echo "Creating $MISSING_SPACES spaces on display $MAIN_DISPLAY..."
|
||||||
|
|
||||||
for i in $(seq 1 $MISSING_SPACES); do
|
for i in $(seq 1 $MISSING_SPACES); do
|
||||||
yabai -m space --create
|
yabai -m space --create
|
||||||
echo "Created space $((CURRENT_SPACE_COUNT + i))"
|
echo "Created space $((CURRENT_SPACE_COUNT + i))"
|
||||||
done
|
done
|
||||||
elif [ "$CURRENT_SPACE_COUNT" -gt "$DESIRED_SPACES" ]; then
|
elif [ "$CURRENT_SPACE_COUNT" -gt "$DESIRED_SPACES" ]; then
|
||||||
EXTRA_SPACES=$((CURRENT_SPACE_COUNT - DESIRED_SPACES))
|
EXTRA_SPACES=$((CURRENT_SPACE_COUNT - DESIRED_SPACES))
|
||||||
echo "Removing $EXTRA_SPACES extra spaces from display $MAIN_DISPLAY..."
|
echo "Removing $EXTRA_SPACES extra spaces from display $MAIN_DISPLAY..."
|
||||||
|
|
||||||
# Get the last space on main display and destroy it
|
# Get the last space on main display and destroy it
|
||||||
for i in $(seq 1 $EXTRA_SPACES); do
|
for i in $(seq 1 $EXTRA_SPACES); do
|
||||||
LAST_SPACE=$(yabai -m query --spaces --display "$MAIN_DISPLAY" | jq 'map(select(."is-native-fullscreen" == false))[-1].index')
|
LAST_SPACE=$(yabai -m query --spaces --display "$MAIN_DISPLAY" | jq 'map(select(."is-native-fullscreen" == false))[-1].index')
|
||||||
yabai -m space --destroy "$LAST_SPACE"
|
yabai -m space --destroy "$LAST_SPACE"
|
||||||
echo "Destroyed space $LAST_SPACE"
|
echo "Destroyed space $LAST_SPACE"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Total spaces on display $MAIN_DISPLAY: $(yabai -m query --spaces --display $MAIN_DISPLAY | jq 'length')"
|
echo "Total spaces on display $MAIN_DISPLAY: $(yabai -m query --spaces --display $MAIN_DISPLAY | jq 'length')"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ exec-on-workspace-change = ['/bin/bash', '-c',
|
||||||
'/run/current-system/sw/bin/sketchybar --trigger aerospace_workspace_changed FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && /etc/profiles/per-user/rayandrew/bin/aerospace-scratchpad hook pull-window $AEROSPACE_PREV_WORKSPACE $AEROSPACE_FOCUSED_WORKSPACE'
|
'/run/current-system/sw/bin/sketchybar --trigger aerospace_workspace_changed FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && /etc/profiles/per-user/rayandrew/bin/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 /bin/bash -c /run/current-system/sw/bin/sketchybar --trigger front_app_switched',
|
'exec-and-forget /bin/bash -c /run/current-system/sw/bin/sketchybar --trigger front_app_switched',
|
||||||
'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger update_windows'
|
'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger update_windows'
|
||||||
]
|
]
|
||||||
|
|
|
||||||
33
config/davmail/davmail.properties
Normal file
33
config/davmail/davmail.properties
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# DavMail configuration
|
||||||
|
# See: http://davmail.sourceforge.net/serversetup.html
|
||||||
|
|
||||||
|
davmail.server=true
|
||||||
|
davmail.disableUpdateCheck=true
|
||||||
|
davmail.mode=O365Manual
|
||||||
|
davmail.url=https://outlook.office365.com/EWS/Exchange.asmx
|
||||||
|
davmail.keepDelay=30
|
||||||
|
|
||||||
|
# Ports
|
||||||
|
davmail.caldavPort=1080
|
||||||
|
davmail.imapPort=1143
|
||||||
|
davmail.ldapPort=1389
|
||||||
|
davmail.popPort=1110
|
||||||
|
davmail.smtpPort=1025
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
davmail.logFilePath=/tmp/davmail.log
|
||||||
|
davmail.logFileSize=1MB
|
||||||
|
|
||||||
|
# OAuth token storage
|
||||||
|
davmail.oauth.tokenFilePath=/Users/rayandrew/.local/state/davmail-tokens
|
||||||
|
|
||||||
|
# Log levels
|
||||||
|
log4j.logger.davmail=WARN
|
||||||
|
log4j.logger.httpclient.wire=WARN
|
||||||
|
log4j.logger.org.apache.commons.httpclient=WARN
|
||||||
|
log4j.rootLogger=WARN
|
||||||
|
|
||||||
|
# log4j.logger.davmail=DEBUG
|
||||||
|
# log4j.logger.httpclient.wire=DEBUG
|
||||||
|
# log4j.logger.org.apache.commons.httpclient=DEBUG
|
||||||
|
# log4j.rootLogger=DEBUG
|
||||||
2
config/direnv/direnv.toml
Normal file
2
config/direnv/direnv.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[global]
|
||||||
|
log_format = "\u001B[2mdirenv: %s\u001B[0m"
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
set fish_greeting
|
set fish_greeting
|
||||||
|
|
||||||
|
# Bootstrap Fisher (reads plugins from fish_plugins)
|
||||||
|
if not functions -q fisher
|
||||||
|
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||||
|
fisher update
|
||||||
|
end
|
||||||
|
|
||||||
function sesh-sessions
|
function sesh-sessions
|
||||||
set -l session (sesh list -t -c | fzf --height 40% --reverse --border-label ' sesh ' --border --prompt '⚡ ')
|
set -l session (sesh list -t -c | fzf --height 40% --reverse --border-label ' sesh ' --border --prompt '⚡ ')
|
||||||
commandline -f repaint
|
commandline -f repaint
|
||||||
|
|
|
||||||
2
config/fish/fish_plugins
Normal file
2
config/fish/fish_plugins
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
jorgebucaran/fisher
|
||||||
|
IlanCosman/tide@v6
|
||||||
|
|
@ -6,6 +6,8 @@ quit-after-last-window-closed = true
|
||||||
gtk-adwaita = false
|
gtk-adwaita = false
|
||||||
# font-family = ${system-font}
|
# font-family = ${system-font}
|
||||||
font-family = Consolas
|
font-family = Consolas
|
||||||
|
font-family = Symbols Nerd Font Mono
|
||||||
|
font-family = DejaVuSansM Nerd Font Mono
|
||||||
font-size = 14
|
font-size = 14
|
||||||
app-notifications = no-clipboard-copy
|
app-notifications = no-clipboard-copy
|
||||||
|
|
||||||
|
|
|
||||||
47
config/home/.mailcap
Normal file
47
config/home/.mailcap
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Mailcap - MIME type handlers for neomutt and other mail clients
|
||||||
|
|
||||||
|
# HTML - terminal inline view (for auto_view)
|
||||||
|
text/html; w3m -dump -T text/html %s; copiousoutput
|
||||||
|
# HTML - open in browser
|
||||||
|
text/html; open %s; nametemplate=%s.html
|
||||||
|
|
||||||
|
# Plain text
|
||||||
|
text/plain; TERM=xterm-256color less %s
|
||||||
|
text/*; TERM=xterm-256color less %s
|
||||||
|
|
||||||
|
# PDF
|
||||||
|
application/pdf; zathura %s
|
||||||
|
application/pdf; open %s
|
||||||
|
|
||||||
|
# Images - terminal (kitty protocol works in ghostty)
|
||||||
|
image/*; kitten icat --clear %s
|
||||||
|
image/*; open %s
|
||||||
|
|
||||||
|
# Video
|
||||||
|
video/*; iina %s
|
||||||
|
video/*; open %s
|
||||||
|
|
||||||
|
# Audio
|
||||||
|
audio/*; mpv --no-video %s
|
||||||
|
audio/*; open %s
|
||||||
|
|
||||||
|
# Microsoft Office - Word
|
||||||
|
application/msword; open %s
|
||||||
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document; open %s
|
||||||
|
|
||||||
|
# Microsoft Office - Excel
|
||||||
|
application/vnd.ms-excel; open %s
|
||||||
|
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; open %s
|
||||||
|
|
||||||
|
# Microsoft Office - PowerPoint
|
||||||
|
application/vnd.ms-powerpoint; open %s
|
||||||
|
application/vnd.openxmlformats-officedocument.presentationml.presentation; open %s
|
||||||
|
|
||||||
|
# Archives - show contents
|
||||||
|
application/zip; unzip -l %s; copiousoutput
|
||||||
|
application/x-tar; tar -tvf %s; copiousoutput
|
||||||
|
application/gzip; tar -tzvf %s; copiousoutput
|
||||||
|
application/x-bzip2; tar -tjvf %s; copiousoutput
|
||||||
|
|
||||||
|
# Fallback - open with default macOS app
|
||||||
|
application/*; open %s
|
||||||
55
config/mbsync/mbsyncrc
Normal file
55
config/mbsync/mbsyncrc
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# mbsync configuration
|
||||||
|
# Run: mbsync -a
|
||||||
|
|
||||||
|
# Personal Gmail account
|
||||||
|
IMAPAccount personal
|
||||||
|
Host imap.gmail.com
|
||||||
|
User raydreww@gmail.com
|
||||||
|
PassCmd "sops -d --extract '[\"personal\"]' ~/dotfiles/home/email/secrets.yaml"
|
||||||
|
TLSType IMAPS
|
||||||
|
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
IMAPStore personal-remote
|
||||||
|
Account personal
|
||||||
|
|
||||||
|
MaildirStore personal-local
|
||||||
|
Path ~/mail/personal/
|
||||||
|
Inbox ~/mail/personal/Inbox
|
||||||
|
SubFolders Verbatim
|
||||||
|
|
||||||
|
Channel personal
|
||||||
|
Far :personal-remote:
|
||||||
|
Near :personal-local:
|
||||||
|
Create Both
|
||||||
|
Expunge Both
|
||||||
|
Patterns * !"[Airmail]/Done" !"[Airmail]/Snooze" !"[Airmail]/To Do" !"[Airmail]/Send Later" !"[Gmail]/All Mail" !"[Gmail]/Important" !"[Gmail]/Starred" !"[Gmail]/Bin"
|
||||||
|
Remove None
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
|
||||||
|
# UChicago account (via DavMail)
|
||||||
|
IMAPAccount uchicago
|
||||||
|
Host 127.0.0.1
|
||||||
|
Port 1143
|
||||||
|
User rayandrew@uchicago.edu
|
||||||
|
PassCmd "sops -d --extract '[\"uchicago\"]' ~/dotfiles/home/email/secrets.yaml"
|
||||||
|
TLSType None
|
||||||
|
AuthMechs LOGIN
|
||||||
|
Timeout 0
|
||||||
|
|
||||||
|
IMAPStore uchicago-remote
|
||||||
|
Account uchicago
|
||||||
|
|
||||||
|
MaildirStore uchicago-local
|
||||||
|
Path ~/mail/uchicago/
|
||||||
|
Inbox ~/mail/uchicago/Inbox
|
||||||
|
SubFolders Verbatim
|
||||||
|
|
||||||
|
Channel uchicago
|
||||||
|
Far :uchicago-remote:
|
||||||
|
Near :uchicago-local:
|
||||||
|
Create Both
|
||||||
|
Expunge Both
|
||||||
|
Patterns * !"[Airmail]/Done" !"[Airmail]/Snooze" !"[Airmail]/To Do" !"[Airmail]/Send Later"
|
||||||
|
Remove None
|
||||||
|
SyncState *
|
||||||
30
config/msmtp/config
Normal file
30
config/msmtp/config
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# msmtp configuration
|
||||||
|
# Default settings for all accounts
|
||||||
|
|
||||||
|
defaults
|
||||||
|
auth on
|
||||||
|
tls on
|
||||||
|
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||||
|
logfile ~/.local/state/msmtp.log
|
||||||
|
|
||||||
|
# Personal Gmail account
|
||||||
|
account personal
|
||||||
|
host smtp.gmail.com
|
||||||
|
from raydreww@gmail.com
|
||||||
|
user raydreww@gmail.com
|
||||||
|
passwordeval "sops -d --extract '[\"personal\"]' ~/dotfiles/home/email/secrets.yaml"
|
||||||
|
tls_starttls off
|
||||||
|
|
||||||
|
# UChicago account (via DavMail)
|
||||||
|
account uchicago
|
||||||
|
host 127.0.0.1
|
||||||
|
port 1025
|
||||||
|
from rayandrew@uchicago.edu
|
||||||
|
user rayandrew@uchicago.edu
|
||||||
|
passwordeval "sops -d --extract '[\"uchicago\"]' ~/dotfiles/home/email/secrets.yaml"
|
||||||
|
auth plain
|
||||||
|
tls off
|
||||||
|
tls_starttls off
|
||||||
|
|
||||||
|
# Default account
|
||||||
|
account default : uchicago
|
||||||
38
config/neomutt/accounts/personal
Normal file
38
config/neomutt/accounts/personal
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Personal Gmail account configuration
|
||||||
|
unmailboxes *
|
||||||
|
|
||||||
|
set ssl_force_tls = yes
|
||||||
|
set certificate_file = /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# GPG
|
||||||
|
set crypt_autosign = yes
|
||||||
|
set crypt_opportunistic_encrypt = no
|
||||||
|
set pgp_use_gpg_agent = yes
|
||||||
|
set mbox_type = Maildir
|
||||||
|
set sort = "threads"
|
||||||
|
|
||||||
|
# Account settings
|
||||||
|
set folder = '~/mail/personal'
|
||||||
|
set from = 'raydreww@gmail.com'
|
||||||
|
set realname = 'Ray Andrew'
|
||||||
|
set spoolfile = '+Inbox'
|
||||||
|
set postponed = '+Drafts'
|
||||||
|
set record = '+Sent'
|
||||||
|
set trash = '+Trash'
|
||||||
|
|
||||||
|
# PGP settings
|
||||||
|
set use_from = yes
|
||||||
|
set pgp_verify_sig = yes
|
||||||
|
set pgp_sign_as = 0x07AA5254804C009F
|
||||||
|
set pgp_timeout = 3600
|
||||||
|
|
||||||
|
# Mailboxes
|
||||||
|
named-mailboxes "p/inbox" =Inbox
|
||||||
|
named-mailboxes "p/drafts" =Drafts
|
||||||
|
named-mailboxes "p/sent" =Sent
|
||||||
|
named-mailboxes "p/important" =Important
|
||||||
|
named-mailboxes "p/trash" =Trash
|
||||||
|
named-mailboxes "p/archive" =Archive
|
||||||
|
|
||||||
|
# Signature
|
||||||
|
set signature = "~/.config/neomutt/signatures/personal"
|
||||||
39
config/neomutt/accounts/uchicago
Normal file
39
config/neomutt/accounts/uchicago
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# UChicago account configuration (via DavMail)
|
||||||
|
unmailboxes *
|
||||||
|
|
||||||
|
set ssl_force_tls = no
|
||||||
|
set certificate_file = /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# GPG
|
||||||
|
set crypt_autosign = no
|
||||||
|
set crypt_opportunistic_encrypt = no
|
||||||
|
set pgp_use_gpg_agent = yes
|
||||||
|
set mbox_type = Maildir
|
||||||
|
set sort = "threads"
|
||||||
|
|
||||||
|
# Account settings
|
||||||
|
set folder = '~/mail/uchicago'
|
||||||
|
set from = 'rayandrew@uchicago.edu'
|
||||||
|
set realname = 'Ray Andrew'
|
||||||
|
set spoolfile = '+Inbox'
|
||||||
|
set postponed = '+Drafts'
|
||||||
|
set record = '+Sent'
|
||||||
|
set trash = '+Trash'
|
||||||
|
|
||||||
|
# PGP settings
|
||||||
|
set use_from = yes
|
||||||
|
set pgp_sign_as = 0xEEF04CFFE9DFE5FC
|
||||||
|
set pgp_verify_sig = yes
|
||||||
|
set pgp_timeout = 3600
|
||||||
|
|
||||||
|
# Mailboxes
|
||||||
|
named-mailboxes "u/inbox" =Inbox
|
||||||
|
named-mailboxes "u/drafts" =Drafts
|
||||||
|
named-mailboxes "u/sent" =Sent
|
||||||
|
named-mailboxes "u/important" =Important
|
||||||
|
named-mailboxes "u/trash" =Trash
|
||||||
|
named-mailboxes "u/archive" =Archive
|
||||||
|
named-mailboxes "u/teaching" =Teaching
|
||||||
|
|
||||||
|
# Signature
|
||||||
|
set signature = "~/.config/neomutt/signatures/uchicago"
|
||||||
93
config/neomutt/colors
Normal file
93
config/neomutt/colors
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
# NeoMutt color scheme - Noctis Azureus
|
||||||
|
# Based on noctis_azureus_ghostty.lua palette
|
||||||
|
# Requires: set color_directcolor = yes
|
||||||
|
|
||||||
|
# Mono settings
|
||||||
|
mono bold bold
|
||||||
|
mono underline underline
|
||||||
|
mono indicator reverse
|
||||||
|
mono error bold
|
||||||
|
|
||||||
|
# General colors - using exact hex from palette
|
||||||
|
color normal '#becfda' default
|
||||||
|
color error '#e66533' default
|
||||||
|
color tilde '#051b29' default
|
||||||
|
color message '#49d6e9' default
|
||||||
|
color markers '#e66533' '#ffffff'
|
||||||
|
color attachment '#becfda' default
|
||||||
|
color search '#051b29' '#49e9a6'
|
||||||
|
color status '#e4b781' '#041520'
|
||||||
|
color indicator '#051b29' '#49d6e9'
|
||||||
|
color tree '#49d6e9' default
|
||||||
|
|
||||||
|
# Sidebar
|
||||||
|
color sidebar_indicator '#051b29' '#49d6e9'
|
||||||
|
color sidebar_highlight '#e4b781' '#0c3f5f'
|
||||||
|
color sidebar_divider '#475e6c' default
|
||||||
|
color sidebar_flagged '#e66533' default
|
||||||
|
color sidebar_new '#49e9a6' default
|
||||||
|
color sidebar_ordinary '#becfda' default
|
||||||
|
|
||||||
|
# Header colors
|
||||||
|
color header '#49ace9' default ".*"
|
||||||
|
color header '#df769b' default "^(From)"
|
||||||
|
color header '#49d6e9' default "^(Subject)"
|
||||||
|
color header '#becfda' default "^(CC|BCC)"
|
||||||
|
color hdrdefault '#49e9a6' default
|
||||||
|
|
||||||
|
# Quoted text (conversation depth)
|
||||||
|
color quoted '#49e9a6' default
|
||||||
|
color quoted1 '#49ace9' default
|
||||||
|
color quoted2 '#49d6e9' default
|
||||||
|
color quoted3 '#e4b781' default
|
||||||
|
color quoted4 '#e66533' default
|
||||||
|
color quoted5 '#e97749' default
|
||||||
|
color signature '#49e9a6' default
|
||||||
|
|
||||||
|
# Body patterns
|
||||||
|
color body '#e97749' default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+"
|
||||||
|
color body '#49ace9' default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+"
|
||||||
|
color body '#49e9a6' default "\`[^\`]*\`"
|
||||||
|
color body '#49ace9' default "^# \.*"
|
||||||
|
color body '#49d6e9' default "^## \.*"
|
||||||
|
color body '#49e9a6' default "^### \.*"
|
||||||
|
color body '#e4b781' default "^(\t| )*(-|\\*) \.*"
|
||||||
|
color body '#49d6e9' default "[;:][-o][)/(|]"
|
||||||
|
color body '#49d6e9' default "[;:][)(|]"
|
||||||
|
color body '#49d6e9' default "[ ][*][^*]*[*][ ]?"
|
||||||
|
color body '#49d6e9' default "[ ]?[*][^*]*[*][ ]"
|
||||||
|
color body '#e66533' default "(BAD signature)"
|
||||||
|
color body '#49d6e9' default "(Good signature)"
|
||||||
|
color body '#475e6c' default "^gpg: Good signature .*"
|
||||||
|
color body '#e4b781' default "^gpg: "
|
||||||
|
color body '#e4b781' '#e66533' "^gpg: BAD signature from.*"
|
||||||
|
mono body bold "^gpg: Good signature"
|
||||||
|
|
||||||
|
# Index colors
|
||||||
|
color index '#becfda' default '.*'
|
||||||
|
color index_author '#df769b' default '.*'
|
||||||
|
color index_number '#49ace9' default
|
||||||
|
color index_subject '#49d6e9' default '.*'
|
||||||
|
color index_date '#475e6c' default
|
||||||
|
color index_size '#475e6c' default
|
||||||
|
color index_flags '#49e9a6' default '.*'
|
||||||
|
|
||||||
|
# New mail - highlighted with bg_highlight
|
||||||
|
color index '#e4b781' '#0c3f5f' "~N"
|
||||||
|
color index_author '#df769b' '#0c3f5f' "~N"
|
||||||
|
color index_subject '#49d6e9' '#0c3f5f' "~N"
|
||||||
|
|
||||||
|
# Flagged mail
|
||||||
|
color index '#e66533' default "~F"
|
||||||
|
color index_author '#e66533' default "~F"
|
||||||
|
|
||||||
|
# Deleted mail
|
||||||
|
color index '#475e6c' default "~D"
|
||||||
|
color index_author '#475e6c' default "~D"
|
||||||
|
color index_subject '#475e6c' default "~D"
|
||||||
|
|
||||||
|
# Tagged mail
|
||||||
|
color index '#49e9a6' default "~T"
|
||||||
|
color index_author '#49e9a6' default "~T"
|
||||||
|
|
||||||
|
color progress '#051b29' '#49d6e9'
|
||||||
65
config/neomutt/keybinds
Normal file
65
config/neomutt/keybinds
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# NeoMutt keybindings
|
||||||
|
|
||||||
|
# Attachment
|
||||||
|
bind attach <return> view-mailcap
|
||||||
|
bind attach l view-mailcap
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
bind editor <space> noop
|
||||||
|
bind editor <Tab> complete-query
|
||||||
|
bind editor ^T complete
|
||||||
|
|
||||||
|
# Pager
|
||||||
|
bind pager c imap-fetch-mail
|
||||||
|
bind pager j next-line
|
||||||
|
bind pager k previous-line
|
||||||
|
bind pager J next-entry
|
||||||
|
bind pager K previous-entry
|
||||||
|
bind pager l view-attachments
|
||||||
|
bind pager,attach h exit
|
||||||
|
bind pager \031 previous-line
|
||||||
|
bind pager \005 next-line
|
||||||
|
bind pager,browser gg top-page
|
||||||
|
bind pager,browser G bottom-page
|
||||||
|
|
||||||
|
# Index
|
||||||
|
bind index G last-entry
|
||||||
|
bind index g noop
|
||||||
|
bind index gg first-entry
|
||||||
|
bind index D delete-message
|
||||||
|
bind index U undelete-message
|
||||||
|
bind index L limit
|
||||||
|
bind index h noop
|
||||||
|
bind index l display-message
|
||||||
|
bind index R group-reply
|
||||||
|
bind index \031 previous-undeleted
|
||||||
|
bind index \005 next-undeleted
|
||||||
|
bind index <tab> sync-mailbox
|
||||||
|
bind index <space> collapse-thread
|
||||||
|
|
||||||
|
# Browser
|
||||||
|
bind browser h goto-parent
|
||||||
|
bind browser l select-entry
|
||||||
|
bind browser,pager,index n search-next
|
||||||
|
bind browser,pager,index N search-opposite
|
||||||
|
|
||||||
|
# Navigation (half page)
|
||||||
|
bind index,pager,browser d half-down
|
||||||
|
bind index,pager,browser u half-up
|
||||||
|
|
||||||
|
# Sidebar
|
||||||
|
bind index,pager \Cp sidebar-prev
|
||||||
|
bind index,pager \Cn sidebar-next
|
||||||
|
bind index,pager o sidebar-open
|
||||||
|
bind index,pager B sidebar-toggle-visible
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
bind index,pager @ compose-to-sender
|
||||||
|
bind index,pager D purge-message
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
macro index,pager a ":set confirmappend=no delete=yes\n<tag-prefix><save-message>=Archive\n<sync-mailbox>:set confirmappend=yes delete=ask-yes\n"
|
||||||
|
macro index,pager n "<tag-prefix><clear-flag>N<untag-pattern>.<enter>\n"
|
||||||
|
macro attach O "<enter-command>unset wait_key<enter><shell-escape>rm -f /tmp/mutt-attach<enter><save-entry><kill-line>/tmp/mutt-attach<enter>^A"
|
||||||
|
macro attach,pager A "|git apply<enter>" "Apply git patch"
|
||||||
|
macro attach,pager P "|git-apply-patch<enter>" "Apply git patch (interactive)"
|
||||||
66
config/neomutt/neomuttrc
Normal file
66
config/neomutt/neomuttrc
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# NeoMutt main configuration
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
set header_cache = "~/.cache/neomutt/headers/"
|
||||||
|
set message_cachedir = "~/.cache/neomutt/messages/"
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
set editor = "emacs -nw"
|
||||||
|
set edit_headers = yes
|
||||||
|
|
||||||
|
# General settings
|
||||||
|
set color_directcolor = yes
|
||||||
|
set implicit_autoview = yes
|
||||||
|
set crypt_use_gpgme = yes
|
||||||
|
alternative_order text/enriched text/plain text
|
||||||
|
set delete = yes
|
||||||
|
set abort_key = "<Esc>"
|
||||||
|
|
||||||
|
# Sidebar
|
||||||
|
set sidebar_visible
|
||||||
|
set sidebar_format = "%D%?F? [%F]?%* %?N?%N/?%S"
|
||||||
|
set mail_check_stats
|
||||||
|
|
||||||
|
# Status bar, date format
|
||||||
|
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 date_format = "%d.%m.%Y %H:%M"
|
||||||
|
set sort = threads
|
||||||
|
set sort_aux = reverse-last-date-received
|
||||||
|
set uncollapse_jump
|
||||||
|
set sort_re
|
||||||
|
set index_format = "%4C %Z %{%b %d} %-15.15L %?E?(%E)&? %s"
|
||||||
|
set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"
|
||||||
|
set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"
|
||||||
|
set send_charset = "utf-8:iso-8859-1:us-ascii"
|
||||||
|
set charset = "utf-8"
|
||||||
|
set arrow_cursor = "no"
|
||||||
|
|
||||||
|
# Pager View Options
|
||||||
|
set pager_index_lines = 10
|
||||||
|
set pager_context = 3
|
||||||
|
set pager_stop
|
||||||
|
set menu_scroll
|
||||||
|
set tilde
|
||||||
|
unset markers
|
||||||
|
|
||||||
|
# MTA (mail transfer agent)
|
||||||
|
set sendmail = 'msmtpq --read-envelope-from --read-recipients'
|
||||||
|
|
||||||
|
# Include keybindings
|
||||||
|
source ~/.config/neomutt/keybinds
|
||||||
|
source ~/.config/neomutt/colors
|
||||||
|
|
||||||
|
# Account switching macros
|
||||||
|
macro index,pager <f2> "<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/uchicago<enter><change-folder>!<enter>"
|
||||||
|
macro index,pager <f3> "<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/personal<enter><change-folder>!<enter>"
|
||||||
|
|
||||||
|
# Register accounts for folder hooks
|
||||||
|
named-mailboxes "p" "~/mail/personal/Inbox"
|
||||||
|
folder-hook ~/mail/personal/ "source ~/.config/neomutt/accounts/personal"
|
||||||
|
|
||||||
|
named-mailboxes "u" "~/mail/uchicago/Inbox"
|
||||||
|
folder-hook ~/mail/uchicago/ "source ~/.config/neomutt/accounts/uchicago"
|
||||||
|
|
||||||
|
# Source primary account (personal)
|
||||||
|
source ~/.config/neomutt/accounts/personal
|
||||||
1
config/neomutt/signatures/personal
Normal file
1
config/neomutt/signatures/personal
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
-- Ray Andrew
|
||||||
1
config/neomutt/signatures/uchicago
Normal file
1
config/neomutt/signatures/uchicago
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
-- Ray Andrew
|
||||||
|
|
@ -150,6 +150,7 @@
|
||||||
age
|
age
|
||||||
ssh-to-age
|
ssh-to-age
|
||||||
nixfmt-rfc-style
|
nixfmt-rfc-style
|
||||||
|
shfmt
|
||||||
];
|
];
|
||||||
DIRENV_LOG_FORMAT = "";
|
DIRENV_LOG_FORMAT = "";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,219 +2,75 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
user,
|
dots,
|
||||||
home-dir,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
|
||||||
./neomutt
|
|
||||||
./mailcap.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
options.custom.email = with lib; {
|
options.custom.email = with lib; {
|
||||||
enable = mkEnableOption "Enable email";
|
enable = mkEnableOption "Enable email";
|
||||||
davmail = mkEnableOption "Enable DavMail";
|
davmail = mkEnableOption "Enable DavMail";
|
||||||
mbsync = mkEnableOption "Enable Mbsync";
|
mbsync = mkEnableOption "Enable Mbsync";
|
||||||
|
neomutt = mkEnableOption "Enable NeoMutt";
|
||||||
|
mailcap = mkEnableOption "Enable mailcap";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf config.custom.email.enable {
|
config = lib.mkIf config.custom.email.enable {
|
||||||
|
# DavMail service (Exchange gateway)
|
||||||
services.davmail = {
|
services.davmail = {
|
||||||
enable = config.custom.email.davmail;
|
enable = config.custom.email.davmail;
|
||||||
settings = {
|
configFile = "${dots}/config/davmail/davmail.properties";
|
||||||
"davmail.mode" = "O365Manual";
|
|
||||||
"davmail.url" = "https://outlook.office365.com/EWS/Exchange.asmx";
|
|
||||||
# davmail.mode = "O365Modern";
|
|
||||||
"davmail.keepDelay" = 30;
|
|
||||||
# log4j.logger.davmail = "DEBUG";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
programs = {
|
# Mbsync service (mail sync)
|
||||||
neomutt = {
|
services.mbsync = {
|
||||||
macros = [
|
enable = config.custom.email.mbsync;
|
||||||
{
|
configFile = "${dots}/config/mbsync/mbsyncrc";
|
||||||
map = [
|
frequency = "*:0/1";
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "<f2>";
|
|
||||||
action = "<sync-mailbox><enter-command>source ~/.config/neomutt/uchicago<enter><change-folder>!<enter>";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "<f3>";
|
|
||||||
action = "<sync-mailbox><enter-command>source ~/.config/neomutt/personal<enter><change-folder>!<enter>";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
mbsync.enable = true;
|
|
||||||
msmtp = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
# Install mail-related packages
|
||||||
mbsync = {
|
home.packages =
|
||||||
enable = config.custom.email.mbsync;
|
with pkgs;
|
||||||
frequency = "*:0/1";
|
[
|
||||||
};
|
isync # mbsync
|
||||||
|
msmtp
|
||||||
|
sops # for password decryption
|
||||||
|
age # for sops age backend
|
||||||
|
]
|
||||||
|
++ lib.optionals config.custom.email.neomutt [
|
||||||
|
# Wrapper script for neomutt with truecolor support
|
||||||
|
(writeShellScriptBin "neomutt" ''
|
||||||
|
export TERMINFO_DIRS="${ncurses}/share/terminfo''${TERMINFO_DIRS:+:$TERMINFO_DIRS}"
|
||||||
|
exec env TERM=xterm-direct ${neomutt}/bin/neomutt "$@"
|
||||||
|
'')
|
||||||
|
]
|
||||||
|
++ lib.optionals config.custom.email.mailcap [
|
||||||
|
mailcap
|
||||||
|
w3m # HTML rendering
|
||||||
|
zathura # PDF viewer
|
||||||
|
kitty # for kitten icat
|
||||||
|
];
|
||||||
|
|
||||||
|
# Symlink config files
|
||||||
|
xdg.configFile = {
|
||||||
|
"msmtp".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/msmtp";
|
||||||
|
"neomutt".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt";
|
||||||
|
"isyncrc".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/mbsync/mbsyncrc";
|
||||||
};
|
};
|
||||||
|
|
||||||
accounts.email =
|
# mailcap symlink
|
||||||
let
|
home.file = lib.mkIf config.custom.email.mailcap {
|
||||||
cat = lib.getExe' pkgs.coreutils "cat";
|
".mailcap".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/home/.mailcap";
|
||||||
in
|
|
||||||
rec {
|
|
||||||
maildirBasePath = "${home-dir}/mail";
|
|
||||||
accounts = lib.mkMerge ([
|
|
||||||
{
|
|
||||||
"personal" = {
|
|
||||||
userName = "raydreww@gmail.com";
|
|
||||||
address = "raydreww@gmail.com";
|
|
||||||
realName = "Ray Andrew";
|
|
||||||
primary = !config.custom.email.davmail;
|
|
||||||
signature = {
|
|
||||||
text = ''
|
|
||||||
-- Ray Andrew
|
|
||||||
'';
|
|
||||||
showSignature = "append";
|
|
||||||
};
|
|
||||||
passwordCommand = "${cat} ${config.sops.secrets."personal".path}";
|
|
||||||
gpg = {
|
|
||||||
key = "1913ECC8FD7076BC8330E11607AA5254804C009F";
|
|
||||||
signByDefault = true;
|
|
||||||
};
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.gmail.com";
|
|
||||||
};
|
|
||||||
imap = {
|
|
||||||
host = "imap.gmail.com";
|
|
||||||
};
|
|
||||||
mbsync = {
|
|
||||||
enable = true;
|
|
||||||
create = "both";
|
|
||||||
expunge = "both";
|
|
||||||
patterns = [
|
|
||||||
"*"
|
|
||||||
"!\"[Airmail]/Done\""
|
|
||||||
"!\"[Airmail]/Snooze\""
|
|
||||||
"!\"[Airmail]/To Do\""
|
|
||||||
"!\"[Airmail]/Send Later\""
|
|
||||||
"!\"[Gmail]/All Mail\""
|
|
||||||
"!\"[Gmail]/Important\""
|
|
||||||
"!\"[Gmail]/Starred\""
|
|
||||||
"!\"[Gmail]/Bin\""
|
|
||||||
];
|
|
||||||
};
|
|
||||||
msmtp = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
neomutt = rec {
|
|
||||||
enable = true;
|
|
||||||
mailboxName = "p";
|
|
||||||
extraConfig = ''
|
|
||||||
set use_from = yes
|
|
||||||
set pgp_verify_sig = yes
|
|
||||||
set pgp_sign_as = 0x07AA5254804C009F
|
|
||||||
set pgp_timeout = 3600
|
|
||||||
named-mailboxes "${mailboxName}/inbox" =Inbox
|
|
||||||
named-mailboxes "${mailboxName}/drafts" =Drafts
|
|
||||||
named-mailboxes "${mailboxName}/sent" =Sent
|
|
||||||
named-mailboxes "${mailboxName}/important" =Important
|
|
||||||
named-mailboxes "${mailboxName}/trash" =Trash
|
|
||||||
named-mailboxes "${mailboxName}/archive" =Archive
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(lib.mkIf config.custom.email.davmail {
|
|
||||||
"uchicago" = {
|
|
||||||
userName = "rayandrew@uchicago.edu";
|
|
||||||
address = "rayandrew@uchicago.edu";
|
|
||||||
realName = "Ray Andrew";
|
|
||||||
primary = true;
|
|
||||||
signature = {
|
|
||||||
text = ''
|
|
||||||
-- Ray Andrew
|
|
||||||
'';
|
|
||||||
showSignature = "append";
|
|
||||||
};
|
|
||||||
passwordCommand = "${cat} ${config.sops.secrets."uchicago".path}";
|
|
||||||
gpg = {
|
|
||||||
key = "0BADFAD0FB93296C84956F9CEEF04CFFE9DFE5FC";
|
|
||||||
signByDefault = false;
|
|
||||||
};
|
|
||||||
smtp = {
|
|
||||||
host = "127.0.0.1";
|
|
||||||
port = 1025;
|
|
||||||
tls = {
|
|
||||||
enable = false;
|
|
||||||
certificatesFile = null;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
imap = {
|
|
||||||
host = "127.0.0.1";
|
|
||||||
port = 1143;
|
|
||||||
tls.enable = false;
|
|
||||||
};
|
|
||||||
mbsync = {
|
|
||||||
enable = true;
|
|
||||||
create = "both";
|
|
||||||
expunge = "both";
|
|
||||||
patterns = [
|
|
||||||
"*"
|
|
||||||
"!\"[Airmail]/Done\""
|
|
||||||
"!\"[Airmail]/Snooze\""
|
|
||||||
"!\"[Airmail]/To Do\""
|
|
||||||
"!\"[Airmail]/Send Later\""
|
|
||||||
];
|
|
||||||
extraConfig.account = {
|
|
||||||
TLSType = "None";
|
|
||||||
AuthMechs = "LOGIN";
|
|
||||||
Timeout = 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
msmtp = {
|
|
||||||
enable = true;
|
|
||||||
extraConfig = {
|
|
||||||
auth = "plain";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
neomutt = rec {
|
|
||||||
enable = true;
|
|
||||||
mailboxName = "u";
|
|
||||||
extraConfig = ''
|
|
||||||
set use_from = yes
|
|
||||||
set pgp_sign_as = 0xEEF04CFFE9DFE5FC
|
|
||||||
set pgp_verify_sig = yes
|
|
||||||
set pgp_timeout = 3600
|
|
||||||
named-mailboxes "${mailboxName}/inbox" =Inbox
|
|
||||||
named-mailboxes "${mailboxName}/drafts" =Drafts
|
|
||||||
named-mailboxes "${mailboxName}/sent" =Sent
|
|
||||||
named-mailboxes "${mailboxName}/important" =Important
|
|
||||||
named-mailboxes "${mailboxName}/trash" =Trash
|
|
||||||
named-mailboxes "${mailboxName}/archive" =Archive
|
|
||||||
named-mailboxes "${mailboxName}/teaching" =Teaching
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
sops = {
|
|
||||||
age.keyFile = "${home-dir}/.config/sops/age/keys.txt";
|
|
||||||
age.generateKey = true;
|
|
||||||
defaultSopsFile = ./secrets.yaml;
|
|
||||||
secrets = {
|
|
||||||
"personal" = { };
|
|
||||||
"uchicago" = { };
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Create mail directories
|
||||||
|
home.activation.createMailDirs = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
mkdir -p ~/mail/personal/Inbox
|
||||||
|
mkdir -p ~/mail/uchicago/Inbox
|
||||||
|
mkdir -p ~/.cache/neomutt/headers
|
||||||
|
mkdir -p ~/.cache/neomutt/messages
|
||||||
|
mkdir -p ~/.local/state
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
|
||||||
w3m = lib.getExe pkgs.w3m;
|
|
||||||
zathura = lib.getExe config.programs.zathura.package;
|
|
||||||
# term = lib.getExe config.programs.kitty.package;
|
|
||||||
term = lib.getExe config.programs.wezterm.package;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.custom.email = with lib; {
|
|
||||||
mailcap = mkEnableOption "Enable mailcap";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.custom.email.mailcap {
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
mailcap
|
|
||||||
];
|
|
||||||
|
|
||||||
home.file.".mailcap" = {
|
|
||||||
text = ''
|
|
||||||
# HTML
|
|
||||||
text/html; ${w3m} -sixel -o tmp_dir=~/.cache/w3m -o auto_image=TRUE -o display_image=1 -T text/html %s; nametemplate=%s.html
|
|
||||||
# text/html; ${w3m} -o inline_img_protocol=4 -o tmp_dir=~/.cache/w3m -o auto_image=TRUE -o display_image=1 -T text/html %s; nametemplate=%s.html
|
|
||||||
|
|
||||||
# This second one is chosen by auto_view due to the copiousoutput tag
|
|
||||||
text/html; ${w3m} -I %{charset} -T text/html -cols 140 -o tmp_dir=~/.cache/w3m -o display_link_number=1 -dump; copiousoutput
|
|
||||||
text/plain; nvim %s
|
|
||||||
|
|
||||||
#PDFs
|
|
||||||
application/x-pdf; ${zathura} '%s'; test=test -n "$DISPLAY"
|
|
||||||
application/pdf; ${zathura} '%s'; test=test -n "$DISPLAY"
|
|
||||||
|
|
||||||
message/rfc822; nvim %s
|
|
||||||
|
|
||||||
#Images
|
|
||||||
# image/png; /usr/bin/feh %s
|
|
||||||
# image/jpeg; /usr/bin/feh %s
|
|
||||||
# image/*; (clear && ${term} +kitten icat %s); needsterminal
|
|
||||||
image/*; (clear && ${term} imgcat %s); needsterminal
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
''
|
|
||||||
# Header colors:
|
|
||||||
color header blue default ".*"
|
|
||||||
color header brightmagenta default "^(From)"
|
|
||||||
color header brightcyan default "^(Subject)"
|
|
||||||
color header brightwhite default "^(CC|BCC)"
|
|
||||||
|
|
||||||
mono bold bold
|
|
||||||
mono underline underline
|
|
||||||
mono indicator reverse
|
|
||||||
mono error bold
|
|
||||||
color normal default default
|
|
||||||
color indicator brightyellow default # currently selected message. default makes bar clear, disabled arrow to save space.
|
|
||||||
color sidebar_highlight red default
|
|
||||||
color sidebar_divider brightblack black
|
|
||||||
color sidebar_flagged red black
|
|
||||||
color sidebar_new green black
|
|
||||||
color normal brightyellow default
|
|
||||||
color error red default
|
|
||||||
color tilde black default
|
|
||||||
color message cyan default
|
|
||||||
color markers red white
|
|
||||||
color attachment white default
|
|
||||||
color search brightmagenta default
|
|
||||||
color status brightyellow black
|
|
||||||
color hdrdefault brightgreen default
|
|
||||||
color quoted green default
|
|
||||||
color quoted1 blue default
|
|
||||||
color quoted2 cyan default
|
|
||||||
color quoted3 yellow default
|
|
||||||
color quoted4 red default
|
|
||||||
color quoted5 brightred default
|
|
||||||
color signature brightgreen default
|
|
||||||
color bold black default
|
|
||||||
color underline black default
|
|
||||||
color normal default default
|
|
||||||
|
|
||||||
color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses
|
|
||||||
color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL
|
|
||||||
color body green default "\`[^\`]*\`" # Green text between ` and `
|
|
||||||
color body brightblue default "^# \.*" # Headings as bold blue
|
|
||||||
color body brightcyan default "^## \.*" # Subheadings as bold cyan
|
|
||||||
color body brightgreen default "^### \.*" # Subsubheadings as bold green
|
|
||||||
color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow
|
|
||||||
color body brightcyan default "[;:][-o][)/(|]" # emoticons
|
|
||||||
color body brightcyan default "[;:][)(|]" # emoticons
|
|
||||||
color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon?
|
|
||||||
color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon?
|
|
||||||
color body red default "(BAD signature)"
|
|
||||||
color body cyan default "(Good signature)"
|
|
||||||
color body brightblack default "^gpg: Good signature .*"
|
|
||||||
color body brightyellow default "^gpg: "
|
|
||||||
color body brightyellow red "^gpg: BAD signature from.*"
|
|
||||||
mono body bold "^gpg: Good signature"
|
|
||||||
# mohttps://neomutt.org/code/config_vars.htmlno body bold "^gpg: BAD signature from.*"
|
|
||||||
color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]"
|
|
||||||
|
|
||||||
# Default index colors:
|
|
||||||
color index yellow default '.*'
|
|
||||||
color index_author red default '.*'
|
|
||||||
color index_number blue default
|
|
||||||
color index_subject cyan default '.*'
|
|
||||||
|
|
||||||
# For new mail:
|
|
||||||
color index brightyellow black "~N"
|
|
||||||
color index_author brightred black "~N"
|
|
||||||
color index_subject brightcyan black "~N"
|
|
||||||
|
|
||||||
color progress black cyan
|
|
||||||
''
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
|
||||||
keybinds = import ./keybind.nix rec {
|
|
||||||
inherit config lib pkgs;
|
|
||||||
};
|
|
||||||
colors = import ./colors.nix rec {
|
|
||||||
inherit config lib pkgs;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
|
|
||||||
options.custom.email = with lib; {
|
|
||||||
neomutt = mkEnableOption "Enable NeoMutt";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf (config.custom.email.enable && config.custom.email.neomutt) {
|
|
||||||
xsession.windowManager.i3.config =
|
|
||||||
let
|
|
||||||
i3config = config.xsession.windowManager.i3.config;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
keybindings = lib.mkOptionDefault {
|
|
||||||
"${i3config.modifier}+m" =
|
|
||||||
"exec --no-startup-id ${i3config.terminal} -e ${config.programs.neomutt.package}/bin/neomutt";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
programs.neomutt = {
|
|
||||||
enable = true;
|
|
||||||
vimKeys = false;
|
|
||||||
sort = "threads";
|
|
||||||
unmailboxes = true;
|
|
||||||
binds = keybinds.binds ++ [ ];
|
|
||||||
macros = keybinds.macros ++ [ ];
|
|
||||||
extraConfig = ''
|
|
||||||
set abort_key = "<Esc>"
|
|
||||||
|
|
||||||
# set editor = "nvim"
|
|
||||||
set editor = "emacs -nw"
|
|
||||||
|
|
||||||
set edit_headers = yes
|
|
||||||
set sidebar_visible
|
|
||||||
set sidebar_format = "%D%?F? [%F]?%* %?N?%N/?%S"
|
|
||||||
set mail_check_stats
|
|
||||||
# set new_mail_command="notify-send 'New Email' '%n new messages, %u unread.' &"
|
|
||||||
|
|
||||||
# status bar, date format, finding stuff etc.
|
|
||||||
set status_chars = " *%A"
|
|
||||||
# set status_format = "[ Folder: %f ] [%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 uncollapse_jump
|
|
||||||
set sort_re
|
|
||||||
set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"
|
|
||||||
set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"
|
|
||||||
set send_charset = "utf-8:iso-8859-1:us-ascii"
|
|
||||||
set charset = "utf-8"
|
|
||||||
set arrow_cursor = "no" # Change `color indicator` depending
|
|
||||||
|
|
||||||
# Pager View Options
|
|
||||||
set pager_index_lines = 10 # Shows 10 lines of index when pager is active
|
|
||||||
set pager_context = 3
|
|
||||||
set pager_stop
|
|
||||||
set menu_scroll
|
|
||||||
set tilde
|
|
||||||
unset markers
|
|
||||||
|
|
||||||
${colors}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,316 +0,0 @@
|
||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
binds = [
|
|
||||||
{
|
|
||||||
map = [ "attach" ];
|
|
||||||
key = "<return>";
|
|
||||||
action = "view-mailcap";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "attach" ];
|
|
||||||
key = "l";
|
|
||||||
action = "view-mailcap";
|
|
||||||
}
|
|
||||||
# {
|
|
||||||
# map = [ "attach" ];
|
|
||||||
# key = "O";
|
|
||||||
# action = "<enter-command>unset wait_key<enter><shell-escape>rm -f /tmp/mutt-attach<enter><save-entry><kill-line>/tmp/mutt-attach<enter>^A";
|
|
||||||
# }
|
|
||||||
{
|
|
||||||
map = [ "editor" ];
|
|
||||||
key = "<space>";
|
|
||||||
action = "noop";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "c";
|
|
||||||
action = "imap-fetch-mail";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "G";
|
|
||||||
action = "last-entry";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "g";
|
|
||||||
action = "noop";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "gg";
|
|
||||||
action = "first-entry";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"pager"
|
|
||||||
"attach"
|
|
||||||
];
|
|
||||||
key = "h";
|
|
||||||
action = "exit";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "j";
|
|
||||||
action = "next-line";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "k";
|
|
||||||
action = "previous-line";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "l";
|
|
||||||
action = "view-attachments";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "D";
|
|
||||||
action = "delete-message";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "U";
|
|
||||||
action = "undelete-message";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "L";
|
|
||||||
action = "limit";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "h";
|
|
||||||
action = "noop";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"browser"
|
|
||||||
"pager"
|
|
||||||
"index"
|
|
||||||
];
|
|
||||||
key = "n";
|
|
||||||
action = "search-next";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"browser"
|
|
||||||
"pager"
|
|
||||||
"index"
|
|
||||||
];
|
|
||||||
key = "N";
|
|
||||||
action = "search-opposite";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "l";
|
|
||||||
action = "display-message";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "browser" ];
|
|
||||||
key = "h";
|
|
||||||
action = "goto-parent";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "browser" ];
|
|
||||||
key = "l";
|
|
||||||
action = "select-entry";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"pager"
|
|
||||||
"browser"
|
|
||||||
];
|
|
||||||
key = "gg";
|
|
||||||
action = "top-page";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"pager"
|
|
||||||
"browser"
|
|
||||||
];
|
|
||||||
key = "G";
|
|
||||||
action = "bottom-page";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
"browser"
|
|
||||||
];
|
|
||||||
key = "d";
|
|
||||||
action = "half-down";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
"browser"
|
|
||||||
];
|
|
||||||
key = "u";
|
|
||||||
action = "half-up";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "R";
|
|
||||||
action = "group-reply";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "\\031";
|
|
||||||
action = "previous-undeleted";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "\\005";
|
|
||||||
action = "next-undeleted";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "\\031";
|
|
||||||
action = "previous-line";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "pager" ];
|
|
||||||
key = "\\005";
|
|
||||||
action = "next-line";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "editor" ];
|
|
||||||
key = "<Tab>";
|
|
||||||
action = "complete-query";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
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 = "\\Cp";
|
|
||||||
action = "sidebar-prev-new";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "\\Cn";
|
|
||||||
action = "sidebar-next-new";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "B";
|
|
||||||
action = "sidebar-toggle-visible";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "@";
|
|
||||||
action = "compose-to-sender";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "D";
|
|
||||||
action = "purge-message";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "<tab>";
|
|
||||||
action = "sync-mailbox";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "index" ];
|
|
||||||
key = "<space>";
|
|
||||||
action = "collapse-thread";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "editor" ];
|
|
||||||
key = "<Tab>";
|
|
||||||
action = "complete-query";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [ "editor" ];
|
|
||||||
key = "^T";
|
|
||||||
action = "complete";
|
|
||||||
}
|
|
||||||
# {
|
|
||||||
# map = [
|
|
||||||
# "index"
|
|
||||||
# "pager"
|
|
||||||
# ];
|
|
||||||
# key = "<f2>";
|
|
||||||
# action = "<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/uchicago<enter><change-folder>!<enter>";
|
|
||||||
# }
|
|
||||||
# {
|
|
||||||
# map = [
|
|
||||||
# "index"
|
|
||||||
# "pager"
|
|
||||||
# ];
|
|
||||||
# key = "<f3>";
|
|
||||||
# action = "<sync-mailbox><enter-command>source ~/.config/neomutt/accounts/personal<enter><change-folder>!<enter>";
|
|
||||||
# }
|
|
||||||
# {
|
|
||||||
# map = [ "attach" ];
|
|
||||||
# key = "V";
|
|
||||||
# action = "<pipe-entry>iconv -c --to-code=UTF8 > ~/.cache/mutt-mail.html<enter><shell-escape>xdg-open ~/.cache/mutt-mail.html<enter>";
|
|
||||||
# }
|
|
||||||
];
|
|
||||||
macros = [
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "a";
|
|
||||||
action = ":set confirmappend=no delete=yes\\n<tag-prefix><save-message>=Archive\\n<sync-mailbox>:set confirmappend=yes delete=ask-yes\\n";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"index"
|
|
||||||
"pager"
|
|
||||||
];
|
|
||||||
key = "n";
|
|
||||||
action = "<tag-prefix><clear-flag>N<untag-pattern>.<enter>\\n";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
map = [
|
|
||||||
"attach"
|
|
||||||
];
|
|
||||||
key = "O";
|
|
||||||
action = "<enter-command>unset wait_key<enter><shell-escape>rm -f /tmp/mutt-attach<enter><save-entry><kill-line>/tmp/mutt-attach<enter>^A";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +1,35 @@
|
||||||
personal: ENC[AES256_GCM,data:aaZAYmnoQfGIH6bBneKtTA==,iv:xiy1eCyBhFulfRXGz0WDFLaqPj3kXsMD4Xkk7D4s5XA=,tag:Nk0KsgICo505VEMwVUt3TA==,type:str]
|
personal: ENC[AES256_GCM,data:MG1ryntM2YKyjb0YH/8GYg==,iv:SvwAc1dBl8wc1YWdnOuCNAb5RUNA2vLX87uzOGOaqec=,tag:ixVU3FWGpZqZx/1PD3/3KA==,type:str]
|
||||||
uchicago: ENC[AES256_GCM,data:3ZkuIfvzOkKfQD0iyTk=,iv:aCfFrxDM5Ly/qLdLAQkK2tOxb89dFkCc9RhN5GVSGRw=,tag:7D54pkVX2F6IhM38JOUFQg==,type:str]
|
uchicago: ENC[AES256_GCM,data:LqZTprY/9Li8ab9i0dg=,iv:tLJHXwsoL7PnwonHlnXiaLahr0+fIizsoshE0GFbkn8=,tag:FT5brU6pW7xFxnzpBYU2jA==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
age:
|
||||||
- recipient: age13cfe8fhp4m978qlcur46vkkxepsl93ggwe53kmhue9xtpgr5zu5q4y6ln2
|
- recipient: age13cfe8fhp4m978qlcur46vkkxepsl93ggwe53kmhue9xtpgr5zu5q4y6ln2
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMMTcwTEc5VTdEMlZSK1FI
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxUjF4Nm0yVWFwMUM1Y2hn
|
||||||
c2VVdjJOc3B3V2RGS0pIVGQralJ4MGFwSkRvCm5mVTNxMHUzNythNHVyRG52bVYz
|
SVRhUmEweDNVd3Z2NVpEVW1yaDRYaDhLZ0NZCjE3WkVTWXUrKzE1VGN5ZUtSb2VZ
|
||||||
RVp2d1hKUnpucko1SG01SDdWNFZGV1EKLS0tIDB2OGF1UlUyN2xnRm1WR1RleUhN
|
WnJFRkkwZmJKTm5OWlpMLzlCZHR6aE0KLS0tIFZ3UEFmcTJIYlcrUXhyU1hSMFRK
|
||||||
S1hFWjhCMlNZVC83ZzR4NittcXlCQlUKQO6NHCMwWKwrfwwnwLK/sO4HO6ES+PyT
|
MjhvU0NQamQzcE1sWG5FSmpoajdNc0UKslJWrvq4BIeMoZ6ZSA6anlldGOpUuXrL
|
||||||
dh3tRhPlv7/viO+MtHqUfQ5cbW+OWoic4prfK/UxIz5VeY331kpq+g==
|
PV7pVpTihxWtzPbPV36oPRVoN3GzNZXUPJryExtUzdnufbhfu9LBTw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6
|
- recipient: age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0ajhrbkdqcmpRd2svYmNx
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZ01sMXhvMG5BMmxwa3h1
|
||||||
dHIzRDJTTTVGV3VON0NBZnpaQTdGM2w4aXpNClNqb2Y4Qzg4OWx2a3FNdG5MY1ZQ
|
aXArSkxUNUkwOHAzQnlkYk4vVmEzckZkaFVzCnpYRmpqMW9QM29VTWFnc0NYTURj
|
||||||
R2dOSC9CdzBPM1I5b1lCVnptMGM3eUEKLS0tIGZRM1pSV3J0NlJvQUZBcTVNZGxy
|
REp0OVNPN1lRRUdPWlQrTmhYcEZwbm8KLS0tIFI2dFBzbmQ4Q01PU1BLUXI5eXIy
|
||||||
SS9qQlJiRU1EelZySWpNdWRiTms3ZncKkwp1WT9LWxnJb+yjilikTHRm1fbs89TU
|
Y0ZMMmJTOVRrbXpOVkYxektxOFFkZUEKcjX/wDMvuZ+PzfydOGOf938mCVcFFD/h
|
||||||
1Xzy+GNiZbtm2I6e5XaaD+9d3PFvqqu0OdqrMrTMmiNAys0WhwB8Iw==
|
nGdbXAoE+cD7/rmpaF0Bpm2WqWrkiAvE/csyaWV/HNzQ6JkXp/4jtQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-03-04T21:54:28Z"
|
- recipient: age15vscvpe79l287h8f3hssrj2r45xy0l3ns94zfue2fxlq43cqdsxq58vq3c
|
||||||
mac: ENC[AES256_GCM,data:r+2SOcW7xLHee9kL8369yB6l/Z2XdnzGkeFygSrDgcZVfBfp/fT1xeMvu5tuu8aqsUeJ7lkFD2VKiBue95XSojdlM+5YyTerqdzLyMCRbkRivC3O2xXe90B4hVqm+twE9uu74mIznAQ2e0EO9E0MMlMNBo3EwsEcYA8gyVuB5mc=,iv:plNu3BircQ+kpPaXqlNvYlLAL5V5RX/yiETs+nY1pfw=,tag:7gVuOpzx5YsHtwodIRr4TQ==,type:str]
|
enc: |
|
||||||
pgp: []
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQdVV6Vy9pRmg1ZjR5c01w
|
||||||
|
L1JWWDF6U05RNnNGTjF1VEN6ZCt6SENod2xJCjA1QngrQnJXMi9BdFByT3FPSVVR
|
||||||
|
eUEyd29YQXphZ2VuTmorOWU4MjZ1TmMKLS0tIFNSZG5iV21MSHVBNkZoZW5pV09k
|
||||||
|
eS9JTWRDaVZVN2hLcVF1S2NTdk1TWGMKVnpl9T5ZycSlJmE8M8QY62kxDp5lgagF
|
||||||
|
D6hxceNiqvgGg+GwIRXoVYiVhmNAE1R9dVTyMlAfFa2pxGg7JrPj1A==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2025-12-02T05:42:16Z"
|
||||||
|
mac: ENC[AES256_GCM,data:95V5+/M85gUaeJD8UhkMZCcMbYEnEBIA3qFDSDd0ZoxXQkw+IXy3/C8rV9QPK/Bq/Hv3fPWbs+0CwH5GqhjfaoIlVgo3MBlk6Z1iSuw7MTy8vGOBFWpYBrObib8f9yYIZ74CrpvCHHoFtqP5cKevmHsCvgrJpbkw4gZIhZVkjLk=,iv:0/v8QzgZYc/VMei0qP1PlK4oc4b2ch5VoBEW3P3gXxU=,tag:rFTyhSixSzl1BOIhGDJo+g==,type:str]
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.4
|
version: 3.11.0
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
nerd-fonts.droid-sans-mono
|
nerd-fonts.droid-sans-mono
|
||||||
nerd-fonts.space-mono
|
nerd-fonts.space-mono
|
||||||
nerd-fonts.dejavu-sans-mono
|
nerd-fonts.dejavu-sans-mono
|
||||||
|
nerd-fonts.symbols-only
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
pandoc
|
pandoc
|
||||||
duckdb
|
duckdb
|
||||||
hyperfine
|
hyperfine
|
||||||
|
fastfetch
|
||||||
(pkgs.python311.withPackages (ppkgs: [
|
(pkgs.python311.withPackages (ppkgs: [
|
||||||
ppkgs.numpy
|
ppkgs.numpy
|
||||||
]))
|
]))
|
||||||
|
|
@ -69,10 +70,18 @@
|
||||||
})
|
})
|
||||||
imagemagick
|
imagemagick
|
||||||
spotify-player
|
spotify-player
|
||||||
|
eza
|
||||||
]
|
]
|
||||||
++ lib.optionals pkgs.stdenv.isDarwin [ coreutils ]
|
++ lib.optionals pkgs.stdenv.isDarwin [ coreutils ]
|
||||||
++ (lib.attrValues config.custom.shell.packages);
|
++ (lib.attrValues config.custom.shell.packages);
|
||||||
|
|
||||||
|
home.shellAliases = {
|
||||||
|
ls = "eza";
|
||||||
|
ll = "eza -la --icons --git";
|
||||||
|
la = "eza -a --icons";
|
||||||
|
lt = "eza --tree --level=2 --icons";
|
||||||
|
};
|
||||||
|
|
||||||
programs.bash = {
|
programs.bash = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableVteIntegration = true;
|
enableVteIntegration = true;
|
||||||
|
|
@ -103,6 +112,8 @@
|
||||||
enableFishIntegration = config.programs.fish.enable;
|
enableFishIntegration = config.programs.fish.enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.configFile."direnv/direnv.toml".source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink "${dots}/config/direnv/direnv.toml";
|
||||||
xdg.configFile."sesh".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/sesh";
|
xdg.configFile."sesh".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/sesh";
|
||||||
xdg.configFile."yazi".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/yazi";
|
xdg.configFile."yazi".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/yazi";
|
||||||
xdg.configFile."spotify-player".source =
|
xdg.configFile."spotify-player".source =
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
|
home-dir,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
@ -80,6 +81,13 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
hm.custom = {
|
hm.custom = {
|
||||||
|
environment = {
|
||||||
|
enable = true;
|
||||||
|
variables = {
|
||||||
|
EDITOR = "nvim";
|
||||||
|
SOPS_AGE_KEY_FILE = "${home-dir}/.config/sops/age/keys.txt";
|
||||||
|
};
|
||||||
|
};
|
||||||
emacs.enable = true;
|
emacs.enable = true;
|
||||||
neovim.enable = true;
|
neovim.enable = true;
|
||||||
latex.enable = true;
|
latex.enable = true;
|
||||||
|
|
@ -91,5 +99,12 @@
|
||||||
hammerspoon.enable = true;
|
hammerspoon.enable = true;
|
||||||
kitty.enable = true;
|
kitty.enable = true;
|
||||||
};
|
};
|
||||||
|
email = {
|
||||||
|
enable = true;
|
||||||
|
davmail = true;
|
||||||
|
neomutt = true;
|
||||||
|
mbsync = true;
|
||||||
|
mailcap = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ let
|
||||||
./shared.nix
|
./shared.nix
|
||||||
./${host}
|
./${host}
|
||||||
./${host}/hardware.nix
|
./${host}/hardware.nix
|
||||||
|
../modules/nixos
|
||||||
../nixos
|
../nixos
|
||||||
(
|
(
|
||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
|
|
@ -59,6 +60,7 @@ let
|
||||||
imports = [
|
imports = [
|
||||||
inputs.nix-index-database.homeModules.nix-index
|
inputs.nix-index-database.homeModules.nix-index
|
||||||
inputs.sops-nix.homeManagerModules.sops
|
inputs.sops-nix.homeManagerModules.sops
|
||||||
|
../modules/home-manager
|
||||||
../home
|
../home
|
||||||
]
|
]
|
||||||
++ lib.optional (builtins.pathExists ./${host}/home.nix) ./${host}/home.nix;
|
++ lib.optional (builtins.pathExists ./${host}/home.nix) ./${host}/home.nix;
|
||||||
|
|
@ -114,6 +116,7 @@ let
|
||||||
modules = [
|
modules = [
|
||||||
./shared.nix
|
./shared.nix
|
||||||
./${host}
|
./${host}
|
||||||
|
../modules/darwin
|
||||||
../darwin
|
../darwin
|
||||||
(
|
(
|
||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
|
|
@ -134,6 +137,7 @@ let
|
||||||
inputs.nix-index-database.homeModules.nix-index
|
inputs.nix-index-database.homeModules.nix-index
|
||||||
inputs.sops-nix.homeManagerModules.sops
|
inputs.sops-nix.homeManagerModules.sops
|
||||||
inputs.mac-app-util.homeManagerModules.default
|
inputs.mac-app-util.homeManagerModules.default
|
||||||
|
../modules/home-manager
|
||||||
../home
|
../home
|
||||||
]
|
]
|
||||||
++ lib.optional (builtins.pathExists ./${host}/home.nix) ./${host}/home.nix;
|
++ lib.optional (builtins.pathExists ./${host}/home.nix) ./${host}/home.nix;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
{
|
{
|
||||||
inputs,
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
system,
|
|
||||||
dots,
|
|
||||||
user,
|
user,
|
||||||
hm,
|
|
||||||
host,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
5
modules/darwin/default.nix
Normal file
5
modules/darwin/default.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# Add darwin-specific custom modules here
|
||||||
|
];
|
||||||
|
}
|
||||||
6
modules/home-manager/default.nix
Normal file
6
modules/home-manager/default.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./overrides
|
||||||
|
./environment.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
50
modules/home-manager/environment.nix
Normal file
50
modules/home-manager/environment.nix
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Home Manager environment module
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
mkIf
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.custom.environment;
|
||||||
|
|
||||||
|
# Convert attrset to shell export statements
|
||||||
|
toShellExports =
|
||||||
|
vars:
|
||||||
|
lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: ''export ${name}="${value}"'') vars);
|
||||||
|
|
||||||
|
# Convert attrset to fish set statements
|
||||||
|
toFishSets =
|
||||||
|
vars:
|
||||||
|
lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: ''set -gx ${name} "${value}"'') vars);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.custom.environment = {
|
||||||
|
enable = mkEnableOption "custom environment configuration";
|
||||||
|
|
||||||
|
variables = mkOption {
|
||||||
|
type = types.attrsOf types.str;
|
||||||
|
default = { };
|
||||||
|
description = "Environment variables to set across all shells.";
|
||||||
|
example = {
|
||||||
|
EDITOR = "nvim";
|
||||||
|
SOPS_AGE_KEY_FILE = "$HOME/.config/sops/age/keys.txt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.sessionVariables = cfg.variables;
|
||||||
|
|
||||||
|
# Also add to shell configs for immediate availability
|
||||||
|
programs.bash.bashrcExtra = lib.mkAfter (toShellExports cfg.variables);
|
||||||
|
programs.zsh.initContent = lib.mkAfter (toShellExports cfg.variables);
|
||||||
|
programs.fish.shellInit = lib.mkAfter (toFishSets cfg.variables);
|
||||||
|
};
|
||||||
|
}
|
||||||
181
modules/home-manager/overrides/davmail.nix
Normal file
181
modules/home-manager/overrides/davmail.nix
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
getExe
|
||||||
|
mapAttrsRecursive
|
||||||
|
mkDefault
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkOption
|
||||||
|
optionalAttrs
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.services.davmail;
|
||||||
|
|
||||||
|
isDarwin = pkgs.stdenv.isDarwin;
|
||||||
|
isLinux = pkgs.stdenv.isLinux;
|
||||||
|
|
||||||
|
javaProperties = pkgs.formats.javaProperties { };
|
||||||
|
|
||||||
|
generatedSettingsFile = javaProperties.generate "davmail.properties" cfg.settings;
|
||||||
|
|
||||||
|
# Use configFile if provided, otherwise use generated settings
|
||||||
|
settingsFile = if cfg.configFile != null then cfg.configFile else generatedSettingsFile;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
disabledModules = [ "services/davmail.nix" ];
|
||||||
|
|
||||||
|
meta.maintainers = [ lib.maintainers.bmrips ];
|
||||||
|
|
||||||
|
options.services.davmail = {
|
||||||
|
enable = mkEnableOption "DavMail, an MS Exchange gateway.";
|
||||||
|
|
||||||
|
package = lib.mkPackageOption pkgs "davmail" { };
|
||||||
|
|
||||||
|
configFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Path to a custom davmail.properties configuration file.
|
||||||
|
If set, this file will be used instead of generating one from settings.
|
||||||
|
'';
|
||||||
|
example = "~/.config/davmail/davmail.properties";
|
||||||
|
};
|
||||||
|
|
||||||
|
imitateOutlook = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether DavMail pretends to be Outlook.";
|
||||||
|
example = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
type = javaProperties.type;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Davmail configuration. Refer to
|
||||||
|
<http://davmail.sourceforge.net/serversetup.html>
|
||||||
|
and <http://davmail.sourceforge.net/advanced.html>
|
||||||
|
for details on supported values.
|
||||||
|
'';
|
||||||
|
example = {
|
||||||
|
"davmail.url" = "https://outlook.office365.com/EWS/Exchange.asmx";
|
||||||
|
"davmail.allowRemote" = true;
|
||||||
|
"davmail.imapPort" = 55555;
|
||||||
|
"davmail.bindAddress" = "10.0.1.2";
|
||||||
|
"davmail.smtpSaveInSent" = true;
|
||||||
|
"davmail.folderSizeLimit" = 10;
|
||||||
|
"davmail.caldavAutoSchedule" = false;
|
||||||
|
"log4j.logger.rootLogger" = "DEBUG";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable (mkMerge [
|
||||||
|
# Common configuration for all platforms
|
||||||
|
{
|
||||||
|
home.packages = [ cfg.package ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default settings (only when configFile is not provided)
|
||||||
|
(mkIf (cfg.configFile == null) {
|
||||||
|
services.davmail.settings =
|
||||||
|
mapAttrsRecursive (_: mkDefault) {
|
||||||
|
"davmail.server" = true;
|
||||||
|
"davmail.disableUpdateCheck" = true;
|
||||||
|
"davmail.logFilePath" = "${config.xdg.stateHome}/davmail.log";
|
||||||
|
"davmail.logFileSize" = "1MB";
|
||||||
|
"davmail.mode" = "auto";
|
||||||
|
"davmail.url" = "https://outlook.office365.com/EWS/Exchange.asmx";
|
||||||
|
"davmail.caldavPort" = 1080;
|
||||||
|
"davmail.imapPort" = 1143;
|
||||||
|
"davmail.ldapPort" = 1389;
|
||||||
|
"davmail.popPort" = 1110;
|
||||||
|
"davmail.smtpPort" = 1025;
|
||||||
|
|
||||||
|
"davmail.oauth.tokenFilePath" = "${config.xdg.stateHome}/davmail-tokens";
|
||||||
|
|
||||||
|
"log4j.logger.davmail" = "WARN";
|
||||||
|
"log4j.logger.httpclient.wire" = "WARN";
|
||||||
|
"log4j.logger.org.apache.commons.httpclient" = "WARN";
|
||||||
|
"log4j.rootLogger" = "WARN";
|
||||||
|
}
|
||||||
|
// optionalAttrs cfg.imitateOutlook {
|
||||||
|
"davmail.oauth.clientId" = "d3590ed6-52b3-4102-aeff-aad2292ab01c";
|
||||||
|
"davmail.oauth.redirectUri" = "urn:ietf:wg:oauth:2.0:oob";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Linux-specific: systemd user service
|
||||||
|
(mkIf isLinux {
|
||||||
|
systemd.user.services.davmail = {
|
||||||
|
Unit = {
|
||||||
|
Description = "DavMail POP/IMAP/SMTP Exchange Gateway";
|
||||||
|
After = [
|
||||||
|
"graphical-session.target"
|
||||||
|
"network.target"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
Install.WantedBy = [ "graphical-session.target" ];
|
||||||
|
Service = {
|
||||||
|
Type = "exec";
|
||||||
|
ExecStart = "${getExe cfg.package} ${settingsFile}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
|
||||||
|
CapabilityBoundingSet = [ "" ];
|
||||||
|
DeviceAllow = [ "" ];
|
||||||
|
LockPersonality = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
RemoveIPC = true;
|
||||||
|
RestrictAddressFamilies = [
|
||||||
|
"AF_INET"
|
||||||
|
"AF_INET6"
|
||||||
|
"AF_UNIX"
|
||||||
|
];
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = "@system-service";
|
||||||
|
SystemCallErrorNumber = "EPERM";
|
||||||
|
UMask = "0077";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Darwin-specific: launchd agent
|
||||||
|
(mkIf isDarwin {
|
||||||
|
launchd.agents.davmail = {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
ProgramArguments = [
|
||||||
|
"${getExe cfg.package}"
|
||||||
|
"${settingsFile}"
|
||||||
|
];
|
||||||
|
KeepAlive = true;
|
||||||
|
RunAtLoad = true;
|
||||||
|
StandardErrorPath = "/tmp/davmail.err.log";
|
||||||
|
StandardOutPath = "/tmp/davmail.out.log";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
6
modules/home-manager/overrides/default.nix
Normal file
6
modules/home-manager/overrides/default.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./davmail.nix
|
||||||
|
./mbsync.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
161
modules/home-manager/overrides/mbsync.nix
Normal file
161
modules/home-manager/overrides/mbsync.nix
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
concatStringsSep
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkOption
|
||||||
|
optionalAttrs
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.services.mbsync;
|
||||||
|
|
||||||
|
isDarwin = pkgs.stdenv.isDarwin;
|
||||||
|
isLinux = pkgs.stdenv.isLinux;
|
||||||
|
|
||||||
|
mbsyncOptions = [
|
||||||
|
"--all"
|
||||||
|
]
|
||||||
|
++ lib.optional cfg.verbose "--verbose"
|
||||||
|
++ lib.optional (cfg.configFile != null) "--config ${cfg.configFile}";
|
||||||
|
|
||||||
|
mbsyncCommand = "${cfg.package}/bin/mbsync ${concatStringsSep " " mbsyncOptions}";
|
||||||
|
|
||||||
|
# Convert systemd calendar format to launchd interval (approximate)
|
||||||
|
# Format like "*:0/5" means every 5 minutes
|
||||||
|
# We'll parse simple cases, default to 5 minutes
|
||||||
|
parseFrequencyToSeconds =
|
||||||
|
freq:
|
||||||
|
let
|
||||||
|
# Try to extract minute interval from patterns like "*:0/5" or "*:*:0/30"
|
||||||
|
parts = builtins.match ".*\\*/([0-9]+).*" freq;
|
||||||
|
in
|
||||||
|
if parts != null then (lib.toInt (builtins.head parts)) * 60 else 300;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
disabledModules = [ "services/mbsync.nix" ];
|
||||||
|
|
||||||
|
meta.maintainers = [ lib.maintainers.pjones ];
|
||||||
|
|
||||||
|
options.services.mbsync = {
|
||||||
|
enable = lib.mkEnableOption "mbsync";
|
||||||
|
|
||||||
|
package = lib.mkPackageOption pkgs "isync" { };
|
||||||
|
|
||||||
|
frequency = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "*:0/5";
|
||||||
|
description = ''
|
||||||
|
How often to run mbsync. On Linux, this value is passed to the systemd
|
||||||
|
timer configuration as the onCalendar option. See
|
||||||
|
{manpage}`systemd.time(7)` for more information about the format.
|
||||||
|
On Darwin, this is converted to an approximate interval in seconds.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
verbose = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether mbsync should produce verbose output.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
configFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Optional configuration file to link to use instead of
|
||||||
|
the default file ({file}`~/.mbsyncrc`).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
preExec = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = "mkdir -p %h/mail";
|
||||||
|
description = ''
|
||||||
|
An optional command to run before mbsync executes. This is
|
||||||
|
useful for creating the directories mbsync is going to use.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
postExec = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = "\${pkgs.mu}/bin/mu index";
|
||||||
|
description = ''
|
||||||
|
An optional command to run after mbsync executes successfully.
|
||||||
|
This is useful for running mailbox indexing tools.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable (mkMerge [
|
||||||
|
# Linux-specific: systemd user service and timer
|
||||||
|
(mkIf isLinux {
|
||||||
|
systemd.user.services.mbsync = {
|
||||||
|
Unit = {
|
||||||
|
Description = "mbsync mailbox synchronization";
|
||||||
|
};
|
||||||
|
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = mbsyncCommand;
|
||||||
|
}
|
||||||
|
// (optionalAttrs (cfg.postExec != null) {
|
||||||
|
ExecStartPost = cfg.postExec;
|
||||||
|
})
|
||||||
|
// (optionalAttrs (cfg.preExec != null) {
|
||||||
|
ExecStartPre = cfg.preExec;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.timers.mbsync = {
|
||||||
|
Unit = {
|
||||||
|
Description = "mbsync mailbox synchronization";
|
||||||
|
};
|
||||||
|
|
||||||
|
Timer = {
|
||||||
|
OnCalendar = cfg.frequency;
|
||||||
|
Unit = "mbsync.service";
|
||||||
|
};
|
||||||
|
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "timers.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Darwin-specific: launchd agent
|
||||||
|
(mkIf isDarwin {
|
||||||
|
launchd.agents.mbsync = {
|
||||||
|
enable = true;
|
||||||
|
config =
|
||||||
|
let
|
||||||
|
# Build a script that handles pre/post exec
|
||||||
|
mbsyncScript = pkgs.writeShellScript "mbsync-wrapper" ''
|
||||||
|
set -e
|
||||||
|
${lib.optionalString (cfg.preExec != null) cfg.preExec}
|
||||||
|
${mbsyncCommand}
|
||||||
|
${lib.optionalString (cfg.postExec != null) cfg.postExec}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
ProgramArguments = [ "${mbsyncScript}" ];
|
||||||
|
StartInterval = parseFrequencyToSeconds cfg.frequency;
|
||||||
|
RunAtLoad = true;
|
||||||
|
StandardErrorPath = "/tmp/mbsync.err.log";
|
||||||
|
StandardOutPath = "/tmp/mbsync.out.log";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
5
modules/nixos/default.nix
Normal file
5
modules/nixos/default.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# Add nixos-specific custom modules here
|
||||||
|
];
|
||||||
|
}
|
||||||
22
secrets/wb.enc
Normal file
22
secrets/wb.enc
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue