diff --git a/src/main.sh b/src/main.sh index f301ef6..209d5a0 100755 --- a/src/main.sh +++ b/src/main.sh @@ -5,6 +5,12 @@ set -eu # Application info . "sh/info.sh" +# helper functions +. "sh/helper.sh" + +# tools +. "sh/tools.sh" + # Configuration . "sh/config.sh" @@ -14,9 +20,6 @@ set -eu # awk scripts . "sh/awk.sh" -# tools -. "sh/tools.sh" - # query history . "sh/history.sh" @@ -38,6 +41,9 @@ set -eu # keys . "sh/keys.sh" +# send emails +. "sh/send.sh" + if [ "${1:-}" = "--list-threads" ]; then shift nmquery="$1" @@ -153,6 +159,27 @@ if [ "${1:-}" = "--undelete" ]; then exit fi +if [ "${1:-}" = "--flag" ]; then + shift + [ "$1" = "thread" ] && thread=1 + shift + [ "${thread:-}" ] && field="thread" || field="id" + query="$(echo " $@" | sed "s/\s\(\S\)/ $field:\1/g")" + $NOTMUCH tag +"$TAG_FLAGGED" "$query" + exit +fi + +if [ "${1:-}" = "--unflag" ]; then + shift + [ "$1" = "thread" ] && thread=1 + shift + [ "${thread:-}" ] && field="thread" || field="id" + query="$(echo " $@" | sed "s/\s\(\S\)/ $field:\1/g")" + $NOTMUCH tag -"$TAG_FLAGGED" "$query" + exit +fi + + if [ "${1:-}" = "--purge" ]; then shift # query="$(echo " $@" | sed "s/\s\(\S*\)/ (thread:\1 and tag:del)/g" | sed 's/)\(\s\+\)(/) or (/g')" @@ -226,9 +253,11 @@ if [ "${1:-}" = "--show-thread" ]; then --bind="$KEYS_ARCHIVE:execute($0 --archive message {+5})+reload:$0 --list-messages-in-thread \"$thread\"" \ --bind="$KEYS_DELETE:execute($0 --delete message {+5})+reload:$0 --list-messages-in-thread \"$thread\"" \ --bind="$KEYS_OPEN:execute:$0 --open-part {5}" \ - --bind="$KEYS_FLAG_TOGGLE:execute:echo NOT IMPLEMENTED;read -r t" \ - --bind="$KEYS_REPLY:execute:echo NOT IMPLEMENTED;read -r t" \ - --bind="$KEYS_COMPOSE:execute:echo NOT IMPLEMENTED;read -r t" \ + --bind="$KEYS_FLAG:execute($0 --flag message {+5})+reload:$0 --list-messages-in-thread \"$thread\"" \ + --bind="$KEYS_UNFLAG:execute($0 --unflag message {+5})+reload:$0 --list-messages-in-thread \"$thread\"" \ + --bind="$KEYS_REPLY:execute:$0 --reply {5}" \ + --bind="$KEYS_VIEW_LOGS:execute:$0 --view-logs" \ + --bind="$KEYS_COMPOSE:execute:$0 --compose" \ --bind="focus:change-preview($0 --preview-message {5})+transform-footer:printf '\033[4mMesssage parts\033[0m\n';$0 --show-message-parts {5}" \ --preview="$0 --preview-message {5}" \ --preview-window="$FZF_DEFAULT_PREVIEW_WINDOW" || true) @@ -255,10 +284,100 @@ if [ "${1:-}" = "--list-deleted" ]; then --bind="$KEYS_ENTER:" \ --bind="$KEYS_PURGE_ALL:select-all+execute($0 --purge {+4})+reload:$0 --list-threads \"tag:$TAG_DEL\"" \ --bind="$KEYS_DELETE:execute($0 --purge {+4})+reload:$0 --list-threads \"tag:$TAG_DEL\"" \ - --bind="$KEYS_ENTER_ALTERNATIVE:execute($0 --undelete {+4})+reload:$0 --list-threads \"tag:$TAG_DEL\"" + --bind="$KEYS_ENTER_ALTERNATIVE:execute($0 --undelete {+4})+reload:$0 --list-threads \"tag:$TAG_DEL\"" \ + --bind="$KEYS_VIEW_LOGS:execute:$0 --view-logs" exit fi +if [ "${1:-}" = "--compose" ]; then + label_text=" Select sender " + address=$(list_addresses | $FZF \ + --delimiter="$(printf '\t')" \ + --with-nth=2 \ + --accept-nth=1 \ + --color="label:$ANSICOLORFROM" \ + --tiebreak=index \ + --margin='20%' \ + --bind="$KEYS_DOWN_HP:half-page-down" \ + --bind="$KEYS_UP_HP:half-page-up" \ + --bind="$KEYS_ENTER:accept-or-print-query" \ + --bind="$KEYS_ENTER_ALTERNATIVE:transform:echo \"print(\$FZF_QUERY)+accept\"" \ + --bind="$KEYS_CANCEL:print()+accept" \ + --border=double \ + --border-label="$label_text" | head -1 || true) + tmpfile=$(mktemp --suffix='.eml') + { + echo "From: $PRIMARY_NAME <$PRIMARY_EMAIL>" + echo "To: $address" + echo "Cc: " + echo "Subject: " + echo "" + echo "Message body goes here" + } > "$tmpfile" + $EDITOR "$tmpfile" + # Confirm and send + send "$tmpfile" + rm -f "$tmpfile" + exit +fi + +if [ "${1:-}" = "--reply" ]; then + shift + messageid="$1" + tmpfile=$(mktemp --suffix='.eml') + $NOTMUCH reply id:"$messageid" > "$tmpfile" + $EDITOR "$tmpfile" + # Confirm and send + send "$tmpfile" + rm -f "$tmpfile" + exit +fi + +if [ "${1:-}" = "--sync" ]; then + $NOTMUCH new && $MBSYNC -a && $NOTMUCH new + exit +fi + +if [ "${1:-}" = "--send-test-email" ]; then + tmpfile=$(mktemp --suffix='.eml') + { + echo "From: $PRIMARY_NAME <$PRIMARY_EMAIL>" + echo "To: $PRIMARY_NAME <$PRIMARY_EMAIL>" + echo "Subject: Test E-Mail from $APP_NAME version $APP_VERSION" + echo "" + echo "This is a test email sent from from [$APP_NAME]($APP_WEBSITE)." + } > "$tmpfile" + send "$tmpfile" "force" + rm -f "$tmpfile" + exit +fi + +if [ "${1:-}" = "--view-logs" ]; then + shift + printf "0 Send test message\n1 Close\n" | + $FZF \ + --sync \ + --bind='start:pos(2)' \ + --bind='ctrl-c,ctrl-g,ctrl-q,esc:pos(2)+accept' \ + --bind="enter:transform: [ {1} = 0 ] && $0 --send-test-email || echo accept" \ + --reverse \ + --no-input \ + --header="Here are the latest SMTP logs" \ + --preview-window='60%,border-line,wrap-word,follow,noinfo' \ + --margin='5%,5%,5%,15%' \ + --preview="tail -f \"$SMTPLOGFILE\" | $CATLOG" \ + --with-nth=2.. \ + --accept-nth=1 \ + --header-border='line' \ + --color='border:yellow,header:yellow' || true + exit +fi + +# Set terminal title +if [ "$SET_TERMINAL_TITLE" = "yes" ]; then + printf '\033]0;%s\007' "$WINDOW_TITLE" +fi + # Modes APPEND="append" NWSRCH="search" @@ -268,11 +387,14 @@ ADDRESS_FROM="from-" CMD_SEARCH_ADDRESS="address-" CMD_EDIT_QUERY="edit-query" CMD_GOTO_INBOX="go-to-inbox" +CMD_GOTO_UNREAD="go-to-unread" +CMD_GOTO_FLAGGED="go-to-flagged" while true; do nmquery="${nmquery:-tag:$TAG_INBOX}" [ "$(tail -1 "$NMFHIST")" = "$nmquery" ] || echo "$nmquery" >> "$NMFHIST" cmd=$(list_threads "$nmquery" | $FZF \ + --no-clear \ --header-first \ --header="Query: $nmquery" \ --tiebreak=index \ @@ -301,8 +423,15 @@ while true; do --bind="$KEYS_TAG_REMOVE:execute($0 --tag-modify thread del {+4})+reload:$0 --list-threads \"$nmquery\"" \ --bind="$KEYS_ARCHIVE:execute($0 --archive thread {+4})+reload:$0 --list-threads \"$nmquery\"" \ --bind="$KEYS_DELETE:execute($0 --delete thread {+4})+reload:$0 --list-threads \"$nmquery\"" \ + --bind="$KEYS_FLAG:execute($0 --flag thread {+4})+reload:$0 --list-threads \"$nmquery\"" \ + --bind="$KEYS_UNFLAG:execute($0 --unflag thread {+4})+reload:$0 --list-threads \"$nmquery\"" \ --bind="$KEYS_SEARCH_DELETED:execute:$0 --list-deleted" \ --bind="$KEYS_SEARCH_INBOX:print($CMD_GOTO_INBOX)+accept" \ + --bind="$KEYS_SEARCH_UNREAD:print($CMD_GOTO_UNREAD)+accept" \ + --bind="$KEYS_SEARCH_FLAGGED:print($CMD_GOTO_FLAGGED)+accept" \ + --bind="$KEYS_VIEW_LOGS:execute:$0 --view-logs" \ + --bind="$KEYS_SYNC:execute($0 --sync)+reload:$0 --list-threads \"$nmquery\"" \ + --bind="$KEYS_COMPOSE:execute:$0 --compose" \ --bind="focus:change-preview:$0 --preview-thread {4}" \ --preview="$0 --preview-thread {4}" \ --preview-window="$FZF_DEFAULT_PREVIEW_WINDOW" | head -1 || true) @@ -335,7 +464,9 @@ while true; do ;; esac address=$(list_addresses | $FZF \ - --color="border:$ANSICOLORFROM" \ + --delimiter="$(printf '\t')" \ + --with-nth=2 \ + --accept-nth=1 \ --color="label:$ANSICOLORFROM" \ --tiebreak=index \ --margin='20%' \ @@ -372,9 +503,9 @@ while true; do --border=double \ --border-label=' Query history ' | head -1 || true) ;; - $CMD_GOTO_INBOX) - nmquery="tag:$TAG_INBOX" - ;; + $CMD_GOTO_INBOX) nmquery="tag:$TAG_INBOX" ;; + $CMD_GOTO_UNREAD) nmquery="tag:$TAG_UNREAD" ;; + $CMD_GOTO_FLAGGED) nmquery="tag:$TAG_FLAGGED" ;; *) ;; esac diff --git a/src/sh/config.sh b/src/sh/config.sh index b71d2be..7d58684 100644 --- a/src/sh/config.sh +++ b/src/sh/config.sh @@ -1,11 +1,26 @@ -# Main application configuration. This application does not require a -# configuration file. However, a configuration file may be stored as -# `CONFIGFILE_DEFAULT`. If that file exists, it will be sourced. The path to -# the file may be overwritten by specifying the environment variable -# `CONFIGFILE`. If a configuration file is specified, then it must also exist. -# A configuration file comprises the specification of environment variables -# that are allowed to be set. -CONFIGFILE_DEFAULT="${XDG_CONFIG_HOME:-"$HOME/.config"}/$APP_NAME/config" -CONFIGFILE="${CONFIGFILE:-"$CONFIGFILE_DEFAULT"}" -[ "$CONFIGFILE" != "$CONFIGFILE_DEFAULT" ] && [ ! -f "$CONFIGFILE" ] && err "The configuration file manually specified with the environment variable CONFIGFILE=($CONFIGFILE) does not exist." && exit 1 -[ -f "$CONFIGFILE" ] && . "$CONFIGFILE" +if [ ! "${CONFIG_LOADED:-}" ]; then + # Main application configuration. This application does not require a + # configuration file. However, a configuration file may be stored as + # `CONFIGFILE_DEFAULT`. If that file exists, it will be sourced. The path to + # the file may be overwritten by specifying the environment variable + # `CONFIGFILE`. If a configuration file is specified, then it must also exist. + # A configuration file comprises the specification of environment variables + # that are allowed to be set. + CONFIGFILE_DEFAULT="${XDG_CONFIG_HOME:-"$HOME/.config"}/$APP_NAME/config" + CONFIGFILE="${CONFIGFILE:-"$CONFIGFILE_DEFAULT"}" + [ "$CONFIGFILE" != "$CONFIGFILE_DEFAULT" ] && [ ! -f "$CONFIGFILE" ] && err "The configuration file manually specified with the environment variable CONFIGFILE=($CONFIGFILE) does not exist." && exit 1 + [ -f "$CONFIGFILE" ] && . "$CONFIGFILE" + SET_TERMINAL_TITLE="${SET_TERMINAL_TITLE:-yes}" + + PRIMARY_NAME=${PRIMARY_NAME:-$($NOTMUCH config get user.name)} + PRIMARY_EMAIL=${PRIMARY_EMAIL:-$($NOTMUCH config get user.primary_email)} + + if [ ! "${SMTPLOGFILE:-}" ]; then + SMTPLOGFILE=$(mktemp) + trap 'rm -f "$SMTPLOGFILE"' EXIT INT + fi + + export PRIMARY_NAME PRIMARY_EMAIL SET_TERMINAL_TITLE SMTPLOGFILE + + export CONFIG_LOADED=1 +fi diff --git a/src/sh/email.sh b/src/sh/email.sh new file mode 100644 index 0000000..e69de29 diff --git a/src/sh/helper.sh b/src/sh/helper.sh new file mode 100644 index 0000000..38a6ba1 --- /dev/null +++ b/src/sh/helper.sh @@ -0,0 +1,5 @@ +# Print error message +err() { + echo "$APP_NAME ERROR: $1" > /dev/stderr +} + diff --git a/src/sh/history.sh b/src/sh/history.sh index 33aeffd..756daee 100644 --- a/src/sh/history.sh +++ b/src/sh/history.sh @@ -2,5 +2,6 @@ if [ ! "${HISTORY_LOADED:-}" ]; then export NMFHIST=$(mktemp) touch "$NMFHIST" trap 'rm -f "$NMFHIST"' EXIT INT + export HISTORY_LOADED=1 fi diff --git a/src/sh/keys.sh b/src/sh/keys.sh index 343fe14..c8cc0b3 100644 --- a/src/sh/keys.sh +++ b/src/sh/keys.sh @@ -1,43 +1,63 @@ -# This file defines the keys used in the keybindings -# The keys are comma separated. See `fzf --man` for the possible keys. +if [ ! "${KEYS_LOADED:-}" ]; then + # This file defines the keys used in the keybindings + # The keys are comma separated. See `fzf --man` for the possible keys. -# List -KEYS_DOWN_HP="ctrl-d" -KEYS_UP_HP="ctrl-u" -KEYS_BACK="ctrl-h" -KEYS_ENTER="enter,ctrl-l" -KEYS_CANCEL="esc" -KEYS_ENTER_ALTERNATIVE="alt-enter" -KEYS_CYCLE_DISPLAY="ctrl-space" + # List + KEYS_DOWN_HP="ctrl-d" + KEYS_UP_HP="ctrl-u" + KEYS_BACK="ctrl-h" + KEYS_ENTER="enter,ctrl-l" + KEYS_CANCEL="esc" + KEYS_ENTER_ALTERNATIVE="alt-enter" + KEYS_CYCLE_DISPLAY="ctrl-space" -KEYS_VIEW_SOURCE="alt-v" -KEYS_HTML_PREVIEW="alt-h" -KEYS_TAG_ADD="alt-+" -KEYS_TAG_REMOVE="alt--" -KEYS_ARCHIVE="ctrl-a" -KEYS_DELETE="ctrl-delete" -KEYS_FLAG_TOGGLE="ctrl-x" -KEYS_OPEN="ctrl-o" -KEYS_REPLY="ctrl-r" -KEYS_COMPOSE="ctrl-n" + KEYS_VIEW_SOURCE="alt-v" + KEYS_HTML_PREVIEW="alt-h" + KEYS_TAG_ADD="alt-+" + KEYS_TAG_REMOVE="alt--" + KEYS_ARCHIVE="ctrl-a" + KEYS_DELETE="ctrl-delete" + KEYS_FLAG="ctrl-x" + KEYS_UNFLAG="ctrl-alt-x" + KEYS_OPEN="ctrl-o" + KEYS_REPLY="ctrl-r" + KEYS_COMPOSE="ctrl-n" + KEYS_VIEW_LOGS="alt-0" + KEYS_SYNC="ctrl-s" -# Preview window -KEYS_PREVIEW_DOWN="alt-j" -KEYS_PREVIEW_UP="alt-k" -KEYS_PREVIEW_DOWN_HP="page-up" -KEYS_PREVIEW_UP_HP="page-down" -KEYS_PREVIEW_TOGGLE_SIZE="alt-/" + # Preview window + KEYS_PREVIEW_DOWN="alt-j" + KEYS_PREVIEW_UP="alt-k" + KEYS_PREVIEW_DOWN_HP="page-up" + KEYS_PREVIEW_UP_HP="page-down" + KEYS_PREVIEW_TOGGLE_SIZE="alt-/" -# Keys specific to purge window -KEYS_PURGE_ALL="ctrl-alt-d" + # Keys specific to purge window + KEYS_PURGE_ALL="ctrl-alt-d" -# Change main views -KEYS_SEARCH_TAG_REPLCE="alt-t" -KEYS_SEARCH_TAG_APPEND="alt-T" -KEYS_SEARCH_FROM_REPLCE="alt-s" -KEYS_SEARCH_FROM_APPEND="alt-S" -KEYS_SEARCH_TO_REPLCE="alt-r" -KEYS_SEARCH_TO_APPEND="alt-R" -KEYS_SEARCH_EDIT_QUERY="alt-q" -KEYS_SEARCH_DELETED="alt-d" -KEYS_SEARCH_INBOX="alt-1" + # Change main views + KEYS_SEARCH_TAG_REPLCE="alt-t" + KEYS_SEARCH_TAG_APPEND="alt-T" + KEYS_SEARCH_FROM_REPLCE="alt-s" + KEYS_SEARCH_FROM_APPEND="alt-S" + KEYS_SEARCH_TO_REPLCE="alt-r" + KEYS_SEARCH_TO_APPEND="alt-R" + KEYS_SEARCH_EDIT_QUERY="alt-q" + KEYS_SEARCH_DELETED="alt-d" + KEYS_SEARCH_INBOX="alt-1" + KEYS_SEARCH_UNREAD="alt-2" + KEYS_SEARCH_FLAGGED="alt-3" + + export KEYS_DOWN_HP KEYS_UP_HP KEYS_BACK KEYS_ENTER KEYS_CANCEL \ + KEYS_ENTER_ALTERNATIVE KEYS_CYCLE_DISPLAY KEYS_VIEW_SOURCE \ + KEYS_HTML_PREVIEW KEYS_TAG_ADD KEYS_TAG_REMOVE KEYS_ARCHIVE KEYS_DELETE \ + KEYS_FLAG KEYS_UNFLAG KEYS_OPEN KEYS_REPLY KEYS_COMPOSE KEYS_VIEW_LOGS \ + KEYS_SYNC KEYS_PREVIEW_DOWN KEYS_PREVIEW_UP KEYS_PREVIEW_DOWN_HP \ + KEYS_PREVIEW_UP_HP KEYS_PREVIEW_TOGGLE_SIZE KEYS_SEARCH_TAG_REPLCE \ + KEYS_SEARCH_TAG_APPEND KEYS_SEARCH_FROM_REPLCE KEYS_SEARCH_FROM_APPEND \ + KEYS_SEARCH_TO_REPLCE KEYS_SEARCH_TO_APPEND KEYS_SEARCH_EDIT_QUERY \ + KEYS_SEARCH_DELETED KEYS_SEARCH_INBOX KEYS_SEARCH_UNREAD \ + KEYS_SEARCH_FLAGGED + + export KEYS_LOADED=1 +fi diff --git a/src/sh/lists.sh b/src/sh/lists.sh index c14e384..62ab528 100644 --- a/src/sh/lists.sh +++ b/src/sh/lists.sh @@ -3,7 +3,7 @@ # List the messages within a thread # @argument $1: thread id list_messages_in_thread() { - $NOTMUCH show thread:"$1" \ + $NOTMUCH show --body=false thread:"$1" \ | awk "$AWK_THREADOVERVIEW" \ | sed "s/^\(\S*\)\t\([^\t]*\)\t\(.*\) (\([^()]*\)) (\([^()]*\))$/${COLFROM}\3${COLRESET}\t${COLSUBJ}\2${COLRESET}\t${COLDATE}\4${COLRESET}\t${COLTAGS}\5${COLRESET}\t\1/" } @@ -26,7 +26,7 @@ list_tags() { # List all email addresses list_addresses() { - $NOTMUCH address '*' + $NOTMUCH address '*' | sed "s/^\(.*[^>]\) \?\(<.*>\)\?$/\1 \2\t${COLFROM}\1${COLRESET} ${COLSUBJ}\2${COLRESET}/" } # List query history diff --git a/src/sh/notmuch.sh b/src/sh/notmuch.sh index 84dc863..692c124 100644 --- a/src/sh/notmuch.sh +++ b/src/sh/notmuch.sh @@ -10,7 +10,7 @@ nm_new() { # @argument $1: thread id nm_last_message_in_thread() { # TODO: We may be smarter here that just incorporating excluded messages - $NOTMUCH search --output=messages --offset=-1 thread:"$1" | sed 's/^...//' + $NOTMUCH search --output=messages --sort=oldest-first --offset=-1 thread:"$1" | sed 's/^...//' } # Print the header of a message (with trailing empty line) diff --git a/src/sh/send.sh b/src/sh/send.sh new file mode 100644 index 0000000..a53ca18 --- /dev/null +++ b/src/sh/send.sh @@ -0,0 +1,20 @@ +# Send email +# @argument $1: Path to email file +# @argument $2: if set, don't prompt the user (optional) +send() { + if [ ! "${2:-}" ] && ! ynprompt "Do you want to send this email?" "$($CATEMAIL $tmpfile)"; then + return + fi + $MSMTP -t --read-envelope-from -X "$SMTPLOGFILE" < "$1" >/dev/null 2>&1 || true + log=$(tail -1 "$SMTPLOGFILE") + if [ "${2:-}" ] || echo -n "$log" | grep -q '\bsmtpstatus=250\b'; then + return + fi + # Handle errors + res=$(printf "0 Retry\n1 Edit email\n2 Abort\n" | multiprompt "Could not send the email. What's next?" "$(echo "$log" | $CATLOG)") + case "$res" in + 0) send "$1" ;; + 1) $EDITOR "$1"; send "$1" ;; + 2) return ;; + esac +} diff --git a/src/sh/tags.sh b/src/sh/tags.sh index 5e40fb6..5d40b6b 100644 --- a/src/sh/tags.sh +++ b/src/sh/tags.sh @@ -1,13 +1,25 @@ -# Default tags +if [ ! "${TAGS_LOADED:-}" ]; then + # Default tags -# The deleted tag is by default the first tag defined in the exclude settings. -# If that does not exist, then it is "deleted". -TAG_DEL=${TAG_DEL:-$($NOTMUCH config get search.exclude_tags|head -1)} -TAG_DEL=${TAG_DEL:-deleted} + # The deleted tag is by default the first tag defined in the exclude settings. + # If that does not exist, then it is "deleted". + TAG_DEL=${TAG_DEL:-$($NOTMUCH config get search.exclude_tags|head -1)} + TAG_DEL=${TAG_DEL:-deleted} -# Tag for messages in the inbox -TAG_INBOX=${TAG_INBOX:-inbox} + # Tag for messages in the inbox + TAG_INBOX=${TAG_INBOX:-inbox} -# White-space separates list of tags that are automatically added to new -# emails. These tags will be removed when the message/tread is archived. -TAGS_NEW=${TAGS_NEW:-$($NOTMUCH config get new.tags | xargs echo)} + # White-space separates list of tags that are automatically added to new + # emails. These tags will be removed when the message/tread is archived. + TAGS_NEW=${TAGS_NEW:-$($NOTMUCH config get new.tags | xargs echo)} + + # Tag for messages that are unread + TAG_UNREAD=${TAG_UNREAD:-unread} + + # Tag for flagged messages + TAG_FLAGGED=${TAG_FLAGGED:-flagged} + + export TAG_DEL TAG_INBOX TAGS_NEW TAG_UNREAD TAG_FLAGGED + + export TAGS_LOADED=1 + fi diff --git a/src/sh/tools.sh b/src/sh/tools.sh index f7da87b..24d6ed8 100644 --- a/src/sh/tools.sh +++ b/src/sh/tools.sh @@ -15,6 +15,22 @@ if [ ! "${TOOLS_LOADED:-}" ]; then fi export NOTMUCH + if command -v "msmtp" >/dev/null; then + MSMTP="msmtp" + else + err "Did not find the command-line email sender msmtp." + exit 1 + fi + export MSMTP + + if command -v "mbsync" >/dev/null; then + MBSYNC="mbsync" + else + err "Did not find the command-line IMAP synchronizer mbsync." + exit 1 + fi + export MBSYNC + if command -v "bat" >/dev/null; then CAT="bat" elif command -v "batcat" >/dev/null; then @@ -22,9 +38,11 @@ if [ ! "${TOOLS_LOADED:-}" ]; then fi CATEMAIL=${CAT:+$CAT -l email --style=plain --color=always} CATMD=${CAT:+$CAT -l markdown --style=plain --color=always} + CATLOG=${CAT:+$CAT -l log --style=plain --color=always} CATEMAIL=${CATEMAIL:-cat} - CATEMD=${CATMD:-cat} - export CATEMAIL CATMD + CATMD=${CATMD:-cat} + CATLOG=${CATLOG:-cat} + export CATEMAIL CATMD CATLOG if command -v "pandoc" >/dev/null; then PANDOC="pandoc --from html --to markdown_strict-raw_html" diff --git a/src/sh/varia.sh b/src/sh/varia.sh index a4d188f..21eb19c 100644 --- a/src/sh/varia.sh +++ b/src/sh/varia.sh @@ -4,7 +4,6 @@ # @argument $1: Question # @argument $2: Content to show in preview window # @return: 0 if the user answered "yes" and 1 otherwise. -#!/bin/sh ynprompt() { return $(printf '0 \033[32myes\033[0m\n1 \033[31mno\033[0m\n' | $FZF \ @@ -17,8 +16,44 @@ ynprompt() { --preview-window='60%,border-line' \ --margin='5%,5%,5%,15%' \ --preview="echo \"$2\"" \ - --with-nth=2 \ + --with-nth=2.. \ --accept-nth=1 \ --header-border='line' \ --color='border:yellow,header:yellow') } + +# This prompts the user for a series of options. +# The options are read from stdin in the form "integer\toption\n". +# Prints number +# +# @argument $1: Question +# @argument $2: Content to show in preview window +multiprompt() { + cat | + $FZF \ + --reverse \ + --no-input \ + --header="$1" \ + --preview-window='60%,border-line,wrap-word' \ + --margin='5%,5%,5%,15%' \ + --preview="echo \"$2\"" \ + --with-nth=2.. \ + --accept-nth=1 \ + --header-border='line' \ + --bind="ctrl-c,esc,ctrl-q:" \ + --color='border:yellow,header:yellow' | head -1 || true +} + +# ASCII-encode address +# asciiaddress() { +# firstword=1 +# for word in $*; do +# [ "${firstword:-}" ] || echo -n ' ' && firstword= +# case $word in +# *[![:cntrl:][:print:]]*) echo -n $word ;; +# *) return 0 ;; +# esac +# isascii "$word" && echo -n "$word" || echo -n "=?UTF-8?B?$(echo -n "$word" | base64)?=" +# done +# } +