#!/bin/bash # Enhanced Himalaya Email Management Script # Features: Auto-discovery, smart navigation, streamlined UX # Function to get available message IDs from himalaya get_available_message_ids() { himalaya envelope list | awk 'NR > 2 && /^\| [0-9]/ {gsub(/[| ]/, "", $2); if($2 ~ /^[0-9]+$/) print $2}' | sort -n } # Function to get the latest (most recent) message ID get_latest_message_id() { get_available_message_ids | tail -1 } # Function to find the next valid message ID find_next_message_id() { local current_id="$1" get_available_message_ids | awk -v current="$current_id" '$1 > current {print $1; exit}' } # Function to find the previous valid message ID find_previous_message_id() { local current_id="$1" get_available_message_ids | awk -v current="$current_id" '$1 < current {prev=$1} END {if(prev) print prev}' } # Function to refresh the vim-himalaya buffer refresh_vim_himalaya() { if [ -S "/tmp/nvim-server" ]; then nvim --server /tmp/nvim-server --remote-send "Himalaya" 2>/dev/null fi } # Function to read a single character without waiting for Enter read_char() { stty -echo -icanon time 0 min 1 char=$(dd bs=1 count=1 2>/dev/null) stty echo icanon echo "$char" } # Function to safely run the himalaya command and handle failures run_himalaya_message_read() { local message_id="$1" local temp_output temp_output=$(himalaya message read "$message_id" 2>&1) local exit_code=$? if [ $exit_code -eq 0 ]; then # Choose email processor based on availability local email_processor if [ -f "email_processor.awk" ]; then email_processor="awk -f email_processor.awk" elif command -v python3 >/dev/null 2>&1 && [ -f "email_processor.py" ]; then email_processor="python3 email_processor.py" else email_processor="cat" # fallback to no processing fi # Process email content, then render with glow and display with less echo "$temp_output" | \ $email_processor | \ # bat glow --width 100 -p # less -R -X -F return 0 else echo "Failed to open message $message_id." return 1 fi } # Function to create a task for the current message create_task_for_message() { local message_id="$1" read -p "Task title: " task_title if [ -n "$task_title" ]; then if command -v task >/dev/null 2>&1; then task add "Followup on email $message_id - $task_title" \ --project "Email" \ --due "$(date -d '+1 week' +%Y-%m-%d)" \ --priority "P3" \ --tags "email" echo "Task created for message $message_id." else echo "TaskWarrior not found. Task not created." fi else echo "No task title provided. Task not created." fi } # Function to display the action menu and handle user choice show_action_menu() { local current_id="$1" # Draw a nice border above the menu echo "" echo "════════════════════════════════════════════════════════════════════════════════" echo " ACTIONS" echo "════════════════════════════════════════════════════════════════════════════════" echo "" echo " t) Create task for this message" echo " d) Delete message" echo " a) Archive message" echo " n) Next message" echo " p) Previous message" echo " r) Reopen/redisplay current message" echo " q) Quit" echo "" echo "────────────────────────────────────────────────────────────────────────────────" echo -n "Enter choice: " local choice=$(read_char) echo "$choice" # Echo for feedback # Clear screen after choice is made clear case "$choice" in t|T) create_task_for_message "$current_id" echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" ;; d|D) echo "Deleting message $current_id..." if himalaya message delete "$current_id"; then echo "Message $current_id deleted successfully." refresh_vim_himalaya # Try to open next available message local next_id=$(find_next_message_id "$current_id") if [ -n "$next_id" ]; then echo "Opening next message: $next_id" process_message "$next_id" else echo "No more messages. Exiting." exit 0 fi else echo "Failed to delete message $current_id." echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" fi ;; a|A) echo "Archiving message $current_id..." if himalaya message move Archives "$current_id"; then echo "Message $current_id archived successfully." refresh_vim_himalaya # Try to open next available message local next_id=$(find_next_message_id "$current_id") if [ -n "$next_id" ]; then echo "Opening next message: $next_id" process_message "$next_id" else echo "No more messages. Exiting." exit 0 fi else echo "Failed to archive message $current_id." echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" fi ;; n|N) local next_id=$(find_next_message_id "$current_id") if [ -n "$next_id" ]; then echo "Opening next message: $next_id" process_message "$next_id" else echo "No next message available." echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" fi ;; p|P) local prev_id=$(find_previous_message_id "$current_id") if [ -n "$prev_id" ]; then echo "Opening previous message: $prev_id" process_message "$prev_id" else echo "No previous message available." echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" fi ;; r|R) echo "Reopening message $current_id..." process_message "$current_id" ;; q|Q) echo "Exiting." exit 0 ;; *) echo "Invalid choice. Please try again." echo "Press any key to continue..." read_char > /dev/null process_message "$current_id" ;; esac } # Function to process a message (read and show menu) process_message() { local message_id="$1" local is_fallback="$2" echo "Reading message $message_id..." if run_himalaya_message_read "$message_id"; then show_action_menu "$message_id" else echo "Error reading message $message_id." if [ "$is_fallback" = "true" ]; then # If this was already a fallback attempt, don't try again echo "Unable to read any messages. Exiting." exit 1 else # Try to find a valid message to fall back to echo "Trying to find an available message..." local latest_id=$(get_latest_message_id) if [ -n "$latest_id" ] && [ "$latest_id" != "$message_id" ]; then echo "Opening latest message: $latest_id" process_message "$latest_id" "true" else echo "No valid messages found. Exiting." exit 1 fi fi fi } # Main script logic # Check if message ID is provided, otherwise get the latest if [ -z "$1" ]; then echo "No message ID provided. Finding latest message..." message_id=$(get_latest_message_id) if [ -z "$message_id" ]; then echo "No messages found in inbox." exit 1 fi echo "Latest message ID: $message_id" else message_id="$1" fi # Validate that himalaya is available if ! command -v himalaya >/dev/null 2>&1; then echo "Error: himalaya command not found. Please install himalaya." exit 1 fi # Start processing the message process_message "$message_id"