diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..14b5ffe --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.sh] +indent_style = space +indent_size = 4 + +[bin/*] +indent_style = space +indent_size = 4 diff --git a/.sops.yaml b/.sops.yaml index 723d244..170fb66 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -3,6 +3,12 @@ keys: - &lemur age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6 - &dango age15vscvpe79l287h8f3hssrj2r45xy0l3ns94zfue2fxlq43cqdsxq58vq3c creation_rules: + - path_regex: secrets/wb\.txt$ + key_groups: + - age: + - *pickwick + - *lemur + - *dango - path_regex: home/email/secrets.yaml$ key_groups: - age: diff --git a/bin/b b/bin/b index 2928830..ad621da 100755 --- a/bin/b +++ b/bin/b @@ -10,9 +10,8 @@ title=${2:-} global="$HOME/Personal/bookmarks.txt" -if [ -n "$url" ] -then - echo "$url $title" >> $global +if [ -n "$url" ]; then + echo "$url $title" >>$global else local="$PWD/bookmarks.txt" diff --git a/bin/cb b/bin/cb index 79917e0..c73e1c6 100755 --- a/bin/cb +++ b/bin/cb @@ -19,19 +19,17 @@ WSL_paste() { } CYGWIN_copy() { - cat > /dev/clipboard + cat >/dev/clipboard } CYGWIN_paste() { cat /dev/clipboard } - MAC_copy() { cat | pbcopy } - MAC_paste() { pbpaste } @@ -85,20 +83,20 @@ detect_os() { printf WSL else case "$(uname -s)" in - Linux*) printf LINUX;; - Darwin*) printf MAC;; - CYGWIN*) printf CYGWIN;; + Linux*) printf LINUX ;; + Darwin*) printf MAC ;; + CYGWIN*) printf CYGWIN ;; esac fi } 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_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 - 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 - echo >> /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_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_a_tty && echo "stdout_is_a_tty: 1" >>/tmp/ono || echo "stdout_is_a_tty: 0" >>/tmp/ono + echo >>/tmp/ono } main() { diff --git a/bin/clear-pbcopy b/bin/clear-pbcopy index 779a79f..5bb632a 100755 --- a/bin/clear-pbcopy +++ b/bin/clear-pbcopy @@ -6,7 +6,5 @@ if [ $# == 1 ]; then sleepsec=$1 fi - sleep $sleepsec -pbcopy < /dev/null - +pbcopy "$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 diff --git a/bin/presentation-mode b/bin/presentation-mode index f7d6759..66c95f2 100755 --- a/bin/presentation-mode +++ b/bin/presentation-mode @@ -11,42 +11,42 @@ presentation_left_gaps=80 presentation_right_gaps=80 if [ "$1" == "on" ]; then - # Save original lines with line numbers - grep -n 'outer\.top\|outer\.bottom\|outer\.left\|outer\.right' "$CONFIG_FILE" > "$BACKUP_FILE" + # Save original lines with line numbers + grep -n 'outer\.top\|outer\.bottom\|outer\.left\|outer\.right' "$CONFIG_FILE" >"$BACKUP_FILE" - # Replace with presentation values - 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\.left[[:space:]]*=\).*/\1 ${presentation_left_gaps}/" "$CONFIG_FILE" - sed -i'' -e "s/^\([[:space:]]*outer\.right[[:space:]]*=\).*/\1 ${presentation_right_gaps}/" "$CONFIG_FILE" + # Replace with presentation values + 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\.left[[:space:]]*=\).*/\1 ${presentation_left_gaps}/" "$CONFIG_FILE" + sed -i'' -e "s/^\([[:space:]]*outer\.right[[:space:]]*=\).*/\1 ${presentation_right_gaps}/" "$CONFIG_FILE" - # 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 + # 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 - aerospace reload-config - echo -n "Presentation mode ON" + aerospace reload-config + echo -n "Presentation mode ON" elif [ "$1" == "off" ]; then - if [ ! -f "$BACKUP_FILE" ]; then - echo "Error: No backup found. Run 'presentation-mode on' first." - exit 1 - fi + if [ ! -f "$BACKUP_FILE" ]; then + echo "Error: No backup found. Run 'presentation-mode on' first." + exit 1 + fi - # Restore original values line by line - while IFS=: read -r line_num content; do - # Escape special characters for sed - escaped_content=$(printf '%s\n' "$content" | sed 's/[&/\]/\\&/g') - sed -i'' -e "${line_num}s/.*/${escaped_content}/" "$CONFIG_FILE" - done < "$BACKUP_FILE" + # Restore original values line by line + while IFS=: read -r line_num content; do + # Escape special characters for sed + escaped_content=$(printf '%s\n' "$content" | sed 's/[&/\]/\\&/g') + sed -i'' -e "${line_num}s/.*/${escaped_content}/" "$CONFIG_FILE" + done <"$BACKUP_FILE" - # 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 + # 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 - rm "$BACKUP_FILE" - aerospace reload-config - echo "Presentation mode OFF" + rm "$BACKUP_FILE" + aerospace reload-config + echo "Presentation mode OFF" else - echo "Usage: presentation-mode [on|off]" - exit 1 + echo "Usage: presentation-mode [on|off]" + exit 1 fi diff --git a/bin/wb b/bin/wb new file mode 100755 index 0000000..d72d163 --- /dev/null +++ b/bin/wb @@ -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] [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 +## -------------------------------------------------------------------- diff --git a/bin/yabai-create-space b/bin/yabai-create-space index 7d4d5ab..c1e4246 100755 --- a/bin/yabai-create-space +++ b/bin/yabai-create-space @@ -16,23 +16,23 @@ echo "Desired spaces: $DESIRED_SPACES" yabai -m display --focus "$MAIN_DISPLAY" if [ "$CURRENT_SPACE_COUNT" -lt "$DESIRED_SPACES" ]; then - MISSING_SPACES=$((DESIRED_SPACES - CURRENT_SPACE_COUNT)) - echo "Creating $MISSING_SPACES spaces on display $MAIN_DISPLAY..." + MISSING_SPACES=$((DESIRED_SPACES - CURRENT_SPACE_COUNT)) + echo "Creating $MISSING_SPACES spaces on display $MAIN_DISPLAY..." - for i in $(seq 1 $MISSING_SPACES); do - yabai -m space --create - echo "Created space $((CURRENT_SPACE_COUNT + i))" - done + for i in $(seq 1 $MISSING_SPACES); do + yabai -m space --create + echo "Created space $((CURRENT_SPACE_COUNT + i))" + done elif [ "$CURRENT_SPACE_COUNT" -gt "$DESIRED_SPACES" ]; then - EXTRA_SPACES=$((CURRENT_SPACE_COUNT - DESIRED_SPACES)) - echo "Removing $EXTRA_SPACES extra spaces from display $MAIN_DISPLAY..." + EXTRA_SPACES=$((CURRENT_SPACE_COUNT - DESIRED_SPACES)) + echo "Removing $EXTRA_SPACES extra spaces from display $MAIN_DISPLAY..." - # Get the last space on main display and destroy it - 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') - yabai -m space --destroy "$LAST_SPACE" - echo "Destroyed space $LAST_SPACE" - done + # Get the last space on main display and destroy it + 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') + yabai -m space --destroy "$LAST_SPACE" + echo "Destroyed space $LAST_SPACE" + done fi echo "Total spaces on display $MAIN_DISPLAY: $(yabai -m query --spaces --display $MAIN_DISPLAY | jq 'length')" diff --git a/config/direnv/direnv.toml b/config/direnv/direnv.toml new file mode 100644 index 0000000..1e67cd4 --- /dev/null +++ b/config/direnv/direnv.toml @@ -0,0 +1,2 @@ +[global] +log_format = "\u001B[2mdirenv: %s\u001B[0m" diff --git a/config/fish/config.fish b/config/fish/config.fish index 3753bd1..e06ffd8 100644 --- a/config/fish/config.fish +++ b/config/fish/config.fish @@ -1,5 +1,11 @@ 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 set -l session (sesh list -t -c | fzf --height 40% --reverse --border-label ' sesh ' --border --prompt '⚡ ') commandline -f repaint diff --git a/config/fish/fish_plugins b/config/fish/fish_plugins new file mode 100644 index 0000000..38e7c1d --- /dev/null +++ b/config/fish/fish_plugins @@ -0,0 +1,2 @@ +jorgebucaran/fisher +IlanCosman/tide@v6 diff --git a/config/ghostty/config b/config/ghostty/config index 366e8c5..0471732 100644 --- a/config/ghostty/config +++ b/config/ghostty/config @@ -6,6 +6,8 @@ quit-after-last-window-closed = true gtk-adwaita = false # font-family = ${system-font} font-family = Consolas +font-family = Symbols Nerd Font Mono +font-family = DejaVuSansM Nerd Font Mono font-size = 14 app-notifications = no-clipboard-copy diff --git a/config/home/.mailcap b/config/home/.mailcap new file mode 100644 index 0000000..811bab7 --- /dev/null +++ b/config/home/.mailcap @@ -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 diff --git a/config/msmtp/config b/config/msmtp/config new file mode 100644 index 0000000..a01acc5 --- /dev/null +++ b/config/msmtp/config @@ -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 diff --git a/config/neomutt/colors b/config/neomutt/colors index 40ac56e..aeaf110 100644 --- a/config/neomutt/colors +++ b/config/neomutt/colors @@ -1,10 +1,6 @@ -# NeoMutt color scheme - -# Header colors -color header blue default ".*" -color header brightmagenta default "^(From)" -color header brightcyan default "^(Subject)" -color header brightwhite default "^(CC|BCC)" +# NeoMutt color scheme - Noctis Azureus +# Based on noctis_azureus_ghostty.lua palette +# Requires: set color_directcolor = yes # Mono settings mono bold bold @@ -12,61 +8,86 @@ mono underline underline mono indicator reverse mono error bold -# General colors -color normal default default -color indicator brightyellow default -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 +# 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 brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" -color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" -color body green default "\`[^\`]*\`" -color body brightblue default "^# \.*" -color body brightcyan default "^## \.*" -color body brightgreen default "^### \.*" -color body yellow default "^(\t| )*(-|\\*) \.*" -color body brightcyan default "[;:][-o][)/(|]" -color body brightcyan default "[;:][)(|]" -color body brightcyan default "[ ][*][^*]*[*][ ]?" -color body brightcyan default "[ ]?[*][^*]*[*][ ]" -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.*" +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" -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<>\"]" # Index colors -color index yellow default '.*' -color index_author red default '.*' -color index_number blue default -color index_subject cyan default '.*' +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 -color index brightyellow black "~N" -color index_author brightred black "~N" -color index_subject brightcyan black "~N" +# New mail - highlighted with bg_highlight +color index '#e4b781' '#0c3f5f' "~N" +color index_author '#df769b' '#0c3f5f' "~N" +color index_subject '#49d6e9' '#0c3f5f' "~N" -color progress black cyan +# 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' diff --git a/config/neomutt/keybinds b/config/neomutt/keybinds index 2f4223b..7d947f5 100644 --- a/config/neomutt/keybinds +++ b/config/neomutt/keybinds @@ -48,11 +48,9 @@ bind index,pager,browser d half-down bind index,pager,browser u half-up # Sidebar -bind index,pager \Ck sidebar-prev -bind index,pager \Cj sidebar-next -bind index,pager \Cl sidebar-open -bind index,pager \Cp sidebar-prev-new -bind index,pager \Cn sidebar-next-new +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 @@ -63,3 +61,5 @@ bind index,pager D purge-message macro index,pager a ":set confirmappend=no delete=yes\n=Archive\n:set confirmappend=yes delete=ask-yes\n" macro index,pager n "N.\n" macro attach O "unset wait_keyrm -f /tmp/mutt-attach/tmp/mutt-attach^A" +macro attach,pager A "|git apply" "Apply git patch" +macro attach,pager P "|git-apply-patch" "Apply git patch (interactive)" diff --git a/config/neomutt/neomuttrc b/config/neomutt/neomuttrc index 2da0d8c..640b0a1 100644 --- a/config/neomutt/neomuttrc +++ b/config/neomutt/neomuttrc @@ -9,6 +9,7 @@ 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 diff --git a/flake.nix b/flake.nix index 0fb3d4e..4b7b9d4 100644 --- a/flake.nix +++ b/flake.nix @@ -150,6 +150,7 @@ age ssh-to-age nixfmt-rfc-style + shfmt ]; DIRENV_LOG_FORMAT = ""; }; diff --git a/home/email/default.nix b/home/email/default.nix index 5adf3a6..82fe4ac 100644 --- a/home/email/default.nix +++ b/home/email/default.nix @@ -7,15 +7,12 @@ }: { - imports = [ - ./mailcap.nix - ]; - options.custom.email = with lib; { enable = mkEnableOption "Enable email"; davmail = mkEnableOption "Enable DavMail"; mbsync = mkEnableOption "Enable Mbsync"; neomutt = mkEnableOption "Enable NeoMutt"; + mailcap = mkEnableOption "Enable mailcap"; }; config = lib.mkIf config.custom.email.enable { @@ -33,38 +30,38 @@ }; # Install mail-related packages - home.packages = with pkgs; [ - isync # mbsync - msmtp - sops # for password decryption - age # for sops age backend - ]; + home.packages = + with pkgs; + [ + 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 config - "msmtp/config".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/msmtp/config"; - - # neomutt configs - "neomutt/neomuttrc".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/neomuttrc"; - "neomutt/keybinds".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/keybinds"; - "neomutt/colors".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/colors"; - "neomutt/accounts/personal".source = - config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/accounts/personal"; - "neomutt/accounts/uchicago".source = - config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/accounts/uchicago"; - "neomutt/signatures/personal".source = - config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/signatures/personal"; - "neomutt/signatures/uchicago".source = - config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt/signatures/uchicago"; - - # isync/mbsync config (some tools look here) + "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"; }; - # neomutt program (for the package) - programs.neomutt = lib.mkIf config.custom.email.neomutt { - enable = true; + # mailcap symlink + home.file = lib.mkIf config.custom.email.mailcap { + ".mailcap".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/home/.mailcap"; }; # Create mail directories diff --git a/home/email/mailcap.nix b/home/email/mailcap.nix deleted file mode 100644 index 771691f..0000000 --- a/home/email/mailcap.nix +++ /dev/null @@ -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 - ''; - }; - }; -} diff --git a/home/email/neomutt/colors.nix b/home/email/neomutt/colors.nix deleted file mode 100644 index 6bb1a80..0000000 --- a/home/email/neomutt/colors.nix +++ /dev/null @@ -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 -'' diff --git a/home/email/neomutt/default.nix b/home/email/neomutt/default.nix deleted file mode 100644 index f888047..0000000 --- a/home/email/neomutt/default.nix +++ /dev/null @@ -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 = "" - - # 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} - ''; - }; - }; -} diff --git a/home/email/neomutt/keybind.nix b/home/email/neomutt/keybind.nix deleted file mode 100644 index 6f1e4a7..0000000 --- a/home/email/neomutt/keybind.nix +++ /dev/null @@ -1,316 +0,0 @@ -{ pkgs, ... }: - -{ - binds = [ - { - map = [ "attach" ]; - key = ""; - action = "view-mailcap"; - } - { - map = [ "attach" ]; - key = "l"; - action = "view-mailcap"; - } - # { - # map = [ "attach" ]; - # key = "O"; - # action = "unset wait_keyrm -f /tmp/mutt-attach/tmp/mutt-attach^A"; - # } - { - map = [ "editor" ]; - key = ""; - 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 = ""; - 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 = ""; - action = "sync-mailbox"; - } - { - map = [ "index" ]; - key = ""; - action = "collapse-thread"; - } - { - map = [ "editor" ]; - key = ""; - action = "complete-query"; - } - { - map = [ "editor" ]; - key = "^T"; - action = "complete"; - } - # { - # map = [ - # "index" - # "pager" - # ]; - # key = ""; - # action = "source ~/.config/neomutt/accounts/uchicago!"; - # } - # { - # map = [ - # "index" - # "pager" - # ]; - # key = ""; - # action = "source ~/.config/neomutt/accounts/personal!"; - # } - # { - # map = [ "attach" ]; - # key = "V"; - # action = "iconv -c --to-code=UTF8 > ~/.cache/mutt-mail.htmlxdg-open ~/.cache/mutt-mail.html"; - # } - ]; - macros = [ - { - map = [ - "index" - "pager" - ]; - key = "a"; - action = ":set confirmappend=no delete=yes\\n=Archive\\n:set confirmappend=yes delete=ask-yes\\n"; - } - { - map = [ - "index" - "pager" - ]; - key = "n"; - action = "N.\\n"; - } - { - map = [ - "attach" - ]; - key = "O"; - action = "unset wait_keyrm -f /tmp/mutt-attach/tmp/mutt-attach^A"; - } - ]; -} diff --git a/home/gui.nix b/home/gui.nix index f302db4..6934768 100644 --- a/home/gui.nix +++ b/home/gui.nix @@ -51,6 +51,7 @@ nerd-fonts.droid-sans-mono nerd-fonts.space-mono nerd-fonts.dejavu-sans-mono + nerd-fonts.symbols-only ]; } diff --git a/home/shell.nix b/home/shell.nix index af8cb47..1bd4b61 100644 --- a/home/shell.nix +++ b/home/shell.nix @@ -60,6 +60,7 @@ pandoc duckdb hyperfine + fastfetch (pkgs.python311.withPackages (ppkgs: [ ppkgs.numpy ])) @@ -69,10 +70,18 @@ }) imagemagick spotify-player + eza ] ++ lib.optionals pkgs.stdenv.isDarwin [ coreutils ] ++ (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 = { enable = true; enableVteIntegration = true; @@ -103,6 +112,8 @@ 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."yazi".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/yazi"; xdg.configFile."spotify-player".source = diff --git a/hosts/dango/default.nix b/hosts/dango/default.nix index 88da862..2202b15 100644 --- a/hosts/dango/default.nix +++ b/hosts/dango/default.nix @@ -104,6 +104,7 @@ davmail = true; neomutt = true; mbsync = true; + mailcap = true; }; }; } diff --git a/secrets/wb.enc b/secrets/wb.enc new file mode 100644 index 0000000..98a81fa --- /dev/null +++ b/secrets/wb.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data: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,iv:tZLayFP8i1XJk+9bt401CZO4MfsoL7OCFq4EdnlOONI=,tag:Uy80ZniTGeP5eQp6XPqApw==,type:str]", + "sops": { + "age": [ + { + "recipient": "age13cfe8fhp4m978qlcur46vkkxepsl93ggwe53kmhue9xtpgr5zu5q4y6ln2", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0KzlUMzBtZVJtZ3pjSTJm\naUFPNFhKNUlLU0RhdldUb1puVndMRVYzN1VvCi9xcWtUNTFJa0c0V2xJYnpZbEJD\neW5LZ3MrMHA2V3l1ZmZ5OHhQQ2h1ZU0KLS0tIFNXdmQwd2NUeWd1eElFUnduMGlQ\nbEkvMmFPd3A0OE5zdEpIeVpqR1REVDgKd2WA5uVPu5pJA+lHpU02kNg0TiqjDL+3\nXy+Z5YBzEUxMWPR3wWtzjSYfXlg7i92HD5yUtJl1eUC5V0zlgkLq0Q==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1pdk6dmyxqhdaja5d0nf8f9qjd43hmfahmkure5yrf8al9jyfmd8qfdxwl6", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTT013cm5KbzZJV0Nuc055\nSy9MVXhaNzBURDlieVUvdWpOMjdBYlNkZkJRCmx5VEgvOSs0eTNjRklISmJoV1N4\nRjJIbDE5bFRSbk1WMTdFUUxNSGxjT1EKLS0tIGFZYW93a2pqWEk3QitpTGxqNU1D\nbDUwcWRFVVNvNy96bEQ1TWxmcGFYYWcKSSe09druYvVZlSZBi3J5C8NXFufKbuBj\nMTXKne749rDPHtM72HpoTVUnpjMHsrwn9fhlsIPz+tRW65qdawAxHw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age15vscvpe79l287h8f3hssrj2r45xy0l3ns94zfue2fxlq43cqdsxq58vq3c", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJTlU1MVZ2c01iSXA2Z0dn\nNnlPaWRrOGVZZFA5Y1l4bGhpWnEvc01LSFRvCmNVNjZGKzJhTGhxeG1yWldSbDAv\nK1RJZDJIaU5LbTh3cXNvVTQyZVBIancKLS0tIGM3Nk5weEhXTUFkZU1wcjArdjl1\ncnh1blFYRVRudDlXOXNOMkFMaHRNTmsKXRqbGC4rceRm8vpvEPEXANvDf/OvV5SJ\nV0jIZBzX358oUyMgV/POU6JdtSpBZuRVGxOvp+0d05JRJEV2j1182g==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-12-03T04:52:11Z", + "mac": "ENC[AES256_GCM,data:7pJTcqdqcdfBWVe+B5fHWrKgICv0Ihjo0JvNZQ8JHgf3xZT51KdOnEL+s/slabNK8STbXp6rGngZZHc3OPlKrXWD5Nd4pKE2EW4oLTIdMEiaxyFfJei84ITt9Xu1fRAOQK1gsvq8ZXUjRHXIbgTJ166QnJvN7CfihvNggOmMJTQ=,iv:PUOIejFXXmevKKi3pw+1b2igqcQJq+9VnIYIjOfhPhg=,tag:UEedwG+S9V+8H4UAvSFMOQ==,type:str]", + "version": "3.11.0" + } +}