diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a694793 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +fzf-vcal diff --git a/fzf-vcal b/fzf-vcal deleted file mode 100755 index 865b936..0000000 --- a/fzf-vcal +++ /dev/null @@ -1,456 +0,0 @@ -#!/bin/sh - -set -eu -# TODO: Make sensitive to failures. I don't want to miss appointments! -# TODO Ensure safe use of delimiters - -err() { - echo "❌ $1" >/dev/tty -} - -if [ -z "${FZF_VCAL_USE_EXPORTED:-}" ]; then - # Read configuration - CONFIGFILE="$HOME/.config/fzf-vcal/config" - if [ ! -f "$CONFIGFILE" ]; then - err "Configuration '$CONFIGFILE' not found." - exit 1 - fi - # shellcheck source=/dev/null - . "$CONFIGFILE" - if [ -z "${ROOT:-}" ] || [ -z "${SYNC_CMD:-}" ] || [ -z "${COLLECTION_LABELS:-}" ]; then - err "Configuration is incomplete." - exit 1 - fi - export ROOT - export SYNC_CMD - export COLLECTION_LABELS - - # Tools - if command -v "fzf" >/dev/null; then - FZF="fzf" - else - err "Did not find the command-line fuzzy finder fzf." - exit 1 - fi - export FZF - - if command -v "uuidgen" >/dev/null; then - UUIDGEN="uuidgen" - else - err "Did not find the uuidgen command." - exit 1 - fi - export UUIDGEN - - if command -v "bat" >/dev/null; then - CAT="bat" - elif command -v "batcat" >/dev/null; then - CAT="batcat" - fi - CAT=${CAT:+$CAT --color=always --style=numbers --language=md} - CAT=${CAT:-cat} - export CAT - - ### AWK SCRIPTS - AWK_LINES=$( - cat <<'EOF' -function parse( dt) { - # Get timezone information - dt = ""; - for (i=2; i 1 ? path[depth-1] : ""; - collection = collection in collection2label ? collection2label[collection] : collection; - return FAINT "~ " collection " " gensub(/^[^0-9]*([0-9]{4})([0-9]{2}).*$/, "\\1-\\2", "1", start) " " summary " ;" start OFF -} - -BEGIN { - FS="[:;=]"; - OFS="|" - split(collection_labels, mapping, ";"); - for (map in mapping) - { - split(mapping[map], m, "="); - collection2label[m[1]] = m[2]; - } - # Colors - GREEN = "\033[1;32m"; - RED = "\033[1;31m"; - WHITE = "\033[1;97m"; - CYAN = "\033[1;36m"; - FAINT = "\033[2m"; - OFF = "\033[m"; -} -BEGINFILE { inside = 0; rs = 0; dur = 0; summary = ""; start = "ERROR"; end = "ERROR" } -/^END:VEVENT/ { print start, dur ? start " " end : end, title(start, summary), fn(FILENAME, n, a); nextfile } -/^DTSTART/ && inside { start = parse( dt) } -/^DTEND/ && inside { end = parse( dt) } -/^DURATION/ && inside { end = parse_duration( dt, dta, i, n, a, seps); dur = 1 } -/^[^ ]/ && rs { rs = 0 } -/^ / && rs { summary = summary substr($0, 2); } -/^SUMMARY/ && inside { rs = 1; summary = $0; } -/^BEGIN:VEVENT/ { inside = 1 } -EOF - ) - export AWK_LINES - - AWK_MERGE=$( - cat <<'EOF' -BEGIN { FS="|"; i=0; dlt = -259200; spw = 604800; } -NR == FNR { - i = i + 1; - from[i] = int(($1 + dlt)/ spw); - getline; - to[i] = int(($1 + dlt) / spw); - next -} # Load start and end week numbers from first file - -{ - if (from[FNR] > to[FNR]) - print "FNR", FNR, ":", from[FNR],"-",to[FNR], " ",$0; - for(i=from[FNR]; i<=to[FNR]; i++) { - week[i] = week[i] ? week[i] ";" $4 : $4 - } -} -END { for (i in week) print i, week[i]; } -EOF - ) - export AWK_MERGE - - AWK_PARSE=$( - cat <<'EOF' -function parse( dt) { - # Get timezone information - dt = ""; - for (i=2; i 1 ? path[depth-1] : ""; - collection = collection in collection2label ? collection2label[collection] : collection; - end = dur ? start " " end : end - cmd = "date -d '" start "' +\"%s\"" - cmd | getline start - close(cmd) - cmd = "date -d '" end "' +\"%s\"" - cmd | getline end - close(cmd) - print start, end, collection, summary -} - -BEGIN { - FS="[:;=]"; - split(collection_labels, mapping, ";"); - for (map in mapping) - { - split(mapping[map], m, "="); - collection2label[m[1]] = m[2]; - } - # Colors - GREEN = "\033[1;32m"; - RED = "\033[1;31m"; - WHITE = "\033[1;97m"; - CYAN = "\033[1;36m"; - FAINT = "\033[2m"; - OFF = "\033[m"; -} -/^END:VEVENT/ && inside { print_data(start, dur, end, summary, cmd, collection); exit } -/^DTSTART/ && inside { start = parse( dt) } -/^DTEND/ && inside { end = parse( dt) } -/^DURATION/ && inside { end = parse_duration( dt, dta, i, n, a, seps); dur = 1 } -/^[^ ]/ && rs { rs = 0 } -/^ / && rs { summary = summary substr($0, 2); } -/^SUMMARY/ && inside { rs = 1; summary = $0; } -/^BEGIN:VEVENT/ { inside = 1 } -EOF - ) - export AWK_PARSE - - AWK_WEEKS=$( - cat <<'EOF' -function parse( dt) { - # Get timezone information - dt = ""; - for (i=2; i") + 1) OFF " " RED "/" OFF -} -BEGIN { - GREEN = "\033[1;32m"; - RED = "\033[1;31m"; - WHITE = "\033[1;97m"; - CYAN = "\033[1;36m"; - FAINT = "\033[2m"; - OFF = "\033[m"; -} -/^[0-7] 00:00 -- 00:00/ { dayline = dayline " " c(); next } -/^[0-7] 00:00 -- / { dayline = dayline " <-|" $4 " " c(); next } -/^[0-7] [0-9]{2}:[0-9]{2} -- 00:00/ { dayline = dayline " " $2 "|-> " c(); next } -/^[0-7] [0-9]{2}:[0-9]{2} -- [0-9]{2}:[0-9]{2}/ { dayline = dayline " " $2 " - " $4 " " c(); next } -/^[0-7]$/ && dayline { print dayline " ;" startofweek " +" $0 " days"; } -/^[0-7]$/ { - cmd = "date -d '" startofweek " +" $0 " days' +\"%a %e %b %Y\""; - cmd | getline dayline; - close(cmd); - dayline = GREEN dayline ": " OFF -} -EOF - ) - export AWK_WEEKVIEW - ### END OF AWK SCRIPTS - FZF_VJOUR_USE_EXPORTED="yes" - export FZF_VJOUR_USE_EXPORTED -fi - -__load_approx_data() { - find "$ROOT" -type f -name '*.ics' -print0 | - xargs -0 -P0 \ - awk \ - -v collection_labels="$COLLECTION_LABELS" \ - "$AWK_LINES" -} - -__load_weeks() { - dates=$(awk -F'|' '{ print $1; print $2 }' "$APPROX_DATA_FILE") - file_dates=$(mktemp) - echo "$dates" | date --file="/dev/stdin" +"%s" >"$file_dates" - awk "$AWK_MERGE" "$file_dates" "$APPROX_DATA_FILE" - rm "$file_dates" -} - -__list() { - weeknr=$(date -d "$DISPLAY_DATE" +"%s") - weeknr=$(((weeknr - 259200) / 604800)) # shift, because epoch origin is a Thursday - files=$(grep "^$weeknr " "$WEEKLY_DATA_FILE" | cut -d " " -f 2) - dayofweek=$(date -d "$DISPLAY_DATE" +"%u") - delta=$((1 - dayofweek)) - startofweek=$(date -d "$DISPLAY_DATE -$delta days" +"%D") - # loop over files - sef=$({ - IFS=';' - set -- $files - for file in "$@"; do - file="$ROOT/$file" - awk \ - -v collection_labels="$COLLECTION_LABELS" \ - "$AWK_PARSE" "$file" - done - }) - if [ -n "$sef" ]; then - sef=$(echo "$sef" | while IFS= read -r line; do - set -- $line - starttime="$1" - shift - endtime="$1" - shift - description="$*" - for i in $(seq 0 7); do - daystart=$(date -d "$startofweek +$i days 00:00:00" +"%s") - dayend=$(date -d "$startofweek +$i days 23:59:59" +"%s") - if [ "$starttime" -gt "$daystart" ] && [ "$starttime" -lt "$dayend" ]; then - s=$(date -d "@$starttime" +"%H:%M") - s="$s -" - elif [ "$starttime" -le "$daystart" ] && [ "$endtime" -gt "$daystart" ]; then - s="00:00 -" - else - continue - fi - if [ "$endtime" -gt "$daystart" ] && [ "$endtime" -lt "$dayend" ]; then - e=$(date -d "@$endtime" +"%H:%M") - e="- $e" - elif [ "$endtime" -ge "$dayend" ] && [ "$starttime" -lt "$dayend" ]; then - e="- 00:00" - else - continue - fi - echo "$i $s$e >$description" - done - done) - fi - sef=$({ - echo "$sef" - seq 0 7 - } | sort -n) - echo "$sef" | awk -v startofweek="$startofweek" "$AWK_WEEKVIEW" - #seq -f "$startofweek +%g days" 0 6 | - # LC_ALL=c xargs -I {} date -d "{}" +"%a %e %b %Y" -} - -if [ -z "${APPROX_DATA_FILE:-}" ]; then - echo "GOING TO LOAD" - APPROX_DATA_FILE=$(mktemp) - __load_approx_data >"$APPROX_DATA_FILE" - export APPROX_DATA_FILE -fi -if [ -z "${WEEKLY_DATA_FILE:-}" ]; then - echo "GOING TO LOAD WD" - WEEKLY_DATA_FILE=$(mktemp) - __load_weeks >"$WEEKLY_DATA_FILE" - export WEEKLY_DATA_FILE -fi - -DISPLAY_DATE="today" -if [ "${1:-}" = "--date" ]; then - DISPLAY_DATE="$2" - echo "Jumping to date $2!" -fi -DISPLAY_DATE=$(date -d "$DISPLAY_DATE" +"%D") -DISPLAY_DATE_PREV=$(date -d "$DISPLAY_DATE -1 week" +"%D") -DISPLAY_DATE_NEXT=$(date -d "$DISPLAY_DATE +1 week" +"%D") - -selection=$( ( - cut -d '|' -f 3 "$APPROX_DATA_FILE" - yes " " | head -n 50 - __list -) | - $FZF \ - --tac \ - --no-sort \ - --no-hscroll \ - --ellipsis='' \ - --ansi \ - --no-clear \ - --bind="ctrl-p:become($0 --date '$DISPLAY_DATE_PREV')" \ - --bind="ctrl-n:become($0 --date '$DISPLAY_DATE_NEXT')" \ - --bind="ctrl-l:become($0)") - -if [ -z "$selection" ]; then - rm "$WEEKLY_DATA_FILE" "$APPROX_DATA_FILE" - return 0 -fi - -case "$selection" in -"~"*) - start=$(echo "$selection" | rev | cut -d';' -f 1 | rev) - exec $0 --date "$start" - ;; -*) - day=$(echo "$selection" | rev | cut -d';' -f 1 | rev) - exec $0 --day "$day" - ;; -esac -echo "Going to end..." -echo "$selection" -echo "STOPPING NOW"