From 1dc4c3b0bc85586a83e0a96e72f9d57f5bf34bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=84min=20Baumeler?= Date: Thu, 5 Jun 2025 10:12:17 +0200 Subject: [PATCH] working again - readonly --- fzf-cal | 96 -------- fzf-vcal | 456 +++++++++++++++++++++++++++++++++++++ scripts/build.sh | 11 + src/awk/lines.awk | 79 +++++++ src/{ => awk}/merge.awk | 9 +- src/{ => awk}/parse.awk | 30 ++- src/{ => awk}/weeks.awk | 0 src/{ => awk}/weekview.awk | 4 +- src/main.sh | 223 ++++++++++++++++++ 9 files changed, 801 insertions(+), 107 deletions(-) delete mode 100755 fzf-cal create mode 100755 fzf-vcal create mode 100755 scripts/build.sh create mode 100644 src/awk/lines.awk rename src/{ => awk}/merge.awk (52%) rename src/{ => awk}/parse.awk (67%) rename src/{ => awk}/weeks.awk (100%) rename src/{ => awk}/weekview.awk (64%) create mode 100755 src/main.sh diff --git a/fzf-cal b/fzf-cal deleted file mode 100755 index 5149fe3..0000000 --- a/fzf-cal +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/sh - -set -eu - -. "$HOME/.config/fzf-vcal/config" - -__load_weeks() { - # TODO: Make sensitive to failures. I don't want to miss appointments! - file_weeks=$(mktemp) - find "$ROOT" -type f -name '*.ics' -print0 | - xargs -0 -P0 \ - awk -f "src/weeks.awk" >"$file_weeks" - dates=$(awk -F'|' '{ print $1; print $2 }' "$file_weeks") - file_dates=$(mktemp) - echo "$dates" | date --file="/dev/stdin" +"%s" >"$file_dates" - awk -f "src/merge.awk" "$file_dates" "$file_weeks" - rm "$file_weeks" "$file_dates" -} - -if [ -z "${WEEKLY_DATA:-}" ]; then - WEEKLY_DATA=$(__load_weeks) - export WEEKLY_DATA -fi - -__list() { - weeknr=$(date -d "$DISPLAY_DATE" +"%s") - weeknr=$(((weeknr - 259200) / 604800)) # shift, because epoch origin is a Thursday - files=$(echo "$WEEKLY_DATA" | grep "^$weeknr " | 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 -f "src/parse.awk" "$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" -f "src/weekview.awk" - #seq -f "$startofweek +%g days" 0 6 | - # LC_ALL=c xargs -I {} date -d "{}" +"%a %e %b %Y" -} - -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") - -__list | - fzf \ - --tac \ - --no-sort \ - --ansi \ - --bind="ctrl-p:become($0 --date '$DISPLAY_DATE_PREV')" \ - --bind="ctrl-n:become($0 --date '$DISPLAY_DATE_NEXT')" diff --git a/fzf-vcal b/fzf-vcal new file mode 100755 index 0000000..865b936 --- /dev/null +++ b/fzf-vcal @@ -0,0 +1,456 @@ +#!/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" diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..71c4e4f --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +BOLD="\033[1m" +GREEN="\033[0;32m" +OFF="\033[m" +NAME="fzf-vcal" +SRC="./src/main.sh" +echo "🐔 ${GREEN}Building${OFF} ${BOLD}$NAME${OFF}" +sed -E 's|@@include (.+)$|cat \1|e' "$SRC" >"$NAME" +chmod +x "$NAME" +echo "🥚 ${GREEN}Done${OFF}" diff --git a/src/awk/lines.awk b/src/awk/lines.awk new file mode 100644 index 0000000..50dfb27 --- /dev/null +++ b/src/awk/lines.awk @@ -0,0 +1,79 @@ +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 } diff --git a/src/merge.awk b/src/awk/merge.awk similarity index 52% rename from src/merge.awk rename to src/awk/merge.awk index de8a7a5..6210c8a 100644 --- a/src/merge.awk +++ b/src/awk/merge.awk @@ -1,14 +1,17 @@ BEGIN { FS="|"; i=0; dlt = -259200; spw = 604800; } NR == FNR { i = i + 1; - from[i] = int(($1 + dtl)/ spw); + from[i] = int(($1 + dlt)/ spw); getline; to[i] = int(($1 + dlt) / spw); next } # Load start and end week numbers from first file -{ for(i=from[FNR]; i<=to[FNR]; i++) { - week[i] = week[i] ? week[i] ";" $3 : $3 +{ + 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]; } diff --git a/src/parse.awk b/src/awk/parse.awk similarity index 67% rename from src/parse.awk rename to src/awk/parse.awk index 9502e12..28514fb 100644 --- a/src/parse.awk +++ b/src/awk/parse.awk @@ -30,13 +30,16 @@ function parse_duration( dt, dta, i, n, a, seps) { return dt; } -function print_data(start, dur, end, summary, cmd) { +function print_data(start, dur, end, summary, cmd, collection) { summary = substr(summary, index(summary, ":") + 1); - #gsub("\\\\n", "\n", summary); # one-liner - #gsub("\\\\N", "\n", summary); # one-liner + gsub("\\\\n", " ", summary); # one-liner + gsub("\\\\N", " ", summary); # one-liner gsub("\\\\,", ",", summary); gsub("\\\\;", ";", summary); gsub("\\\\\\\\", "\\", summary); + depth = split(FILENAME, path, "/"); + collection = depth > 1 ? path[depth-1] : ""; + collection = collection in collection2label ? collection2label[collection] : collection; end = dur ? start " " end : end cmd = "date -d '" start "' +\"%s\"" cmd | getline start @@ -44,11 +47,26 @@ function print_data(start, dur, end, summary, cmd) { cmd = "date -d '" end "' +\"%s\"" cmd | getline end close(cmd) - print start, end, summary + print start, end, collection, summary } -BEGIN { FS="[:;=]"; } -/^END:VEVENT/ && inside { print_data(start, dur, end, summary, cmd); exit } +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 } diff --git a/src/weeks.awk b/src/awk/weeks.awk similarity index 100% rename from src/weeks.awk rename to src/awk/weeks.awk diff --git a/src/weekview.awk b/src/awk/weekview.awk similarity index 64% rename from src/weekview.awk rename to src/awk/weekview.awk index baac960..dae6325 100644 --- a/src/weekview.awk +++ b/src/awk/weekview.awk @@ -1,5 +1,5 @@ function c() { - return substr($0, index($0, ">") + 1) " " RED "/" OFF + return CYAN substr($0, index($0, ">") + 1) OFF " " RED "/" OFF } BEGIN { GREEN = "\033[1;32m"; @@ -13,7 +13,7 @@ BEGIN { /^[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; } +/^[0-7]$/ && dayline { print dayline " ;" startofweek " +" $0 " days"; } /^[0-7]$/ { cmd = "date -d '" startofweek " +" $0 " days' +\"%a %e %b %Y\""; cmd | getline dayline; diff --git a/src/main.sh b/src/main.sh new file mode 100755 index 0000000..b6c215f --- /dev/null +++ b/src/main.sh @@ -0,0 +1,223 @@ +#!/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' +@@include src/awk/lines.awk +EOF + ) + export AWK_LINES + + AWK_MERGE=$( + cat <<'EOF' +@@include src/awk/merge.awk +EOF + ) + export AWK_MERGE + + AWK_PARSE=$( + cat <<'EOF' +@@include src/awk/parse.awk +EOF + ) + export AWK_PARSE + + AWK_WEEKS=$( + cat <<'EOF' +@@include src/awk/weeks.awk +EOF + ) + export AWK_WEEKS + + AWK_WEEKVIEW=$( + cat <<'EOF' +@@include src/awk/weekview.awk +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"