300 lines
7.1 KiB
Bash
Executable File
300 lines
7.1 KiB
Bash
Executable File
#!/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_WEEKVIEW=$(
|
|
cat <<'EOF'
|
|
@@include src/awk/weekview.awk
|
|
EOF
|
|
)
|
|
export AWK_WEEKVIEW
|
|
|
|
AWK_DAYVIEW=$(
|
|
cat <<'EOF'
|
|
@@include src/awk/dayview.awk
|
|
EOF
|
|
)
|
|
export AWK_DAYVIEW
|
|
### 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 $2; print $3 }' "$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"
|
|
}
|
|
|
|
__show_day() {
|
|
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-)
|
|
# Find relevant files in list of week files
|
|
sef=$({
|
|
set -- $files
|
|
for file in "$@"; do
|
|
file="$ROOT/$file"
|
|
awk \
|
|
-v collection_labels="$COLLECTION_LABELS" \
|
|
"$AWK_PARSE" "$file"
|
|
done
|
|
})
|
|
if [ -n "$sef" ]; then
|
|
today=$(date -d "$DISPLAY_DATE" +"%D")
|
|
sef=$(echo "$sef" | while IFS= read -r line; do
|
|
set -- $line
|
|
starttime="$1"
|
|
shift
|
|
endtime="$1"
|
|
shift
|
|
fpath="$1"
|
|
shift
|
|
description=$(echo "$*" | sed 's/|/:/g') # we will use | as delimiter
|
|
#
|
|
daystart=$(date -d "$today 00:00:00" +"%s")
|
|
dayend=$(date -d "$today 23:59:59" +"%s")
|
|
line=""
|
|
if [ "$starttime" -gt "$daystart" ] && [ "$starttime" -lt "$dayend" ]; then
|
|
s=$(date -d "@$starttime" +"%H:%M")
|
|
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")
|
|
elif [ "$endtime" -ge "$dayend" ] && [ "$starttime" -lt "$dayend" ]; then
|
|
e="00:00"
|
|
else
|
|
continue
|
|
fi
|
|
echo "$s|$e|$fpath|$description"
|
|
done)
|
|
fi
|
|
GREEN="\033[1;32m"
|
|
OFF="\033[m"
|
|
echo "|🗓️ $GREEN $(date -d "$DISPLAY_DATE" +"%a %e %b %Y")$OFF"
|
|
echo ""
|
|
(
|
|
echo "$sef"
|
|
seq 8 18 | sort -n
|
|
) | awk "$AWK_DAYVIEW"
|
|
}
|
|
|
|
__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=$({
|
|
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
|
|
#fpath="$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
|
|
APPROX_DATA_FILE=$(mktemp)
|
|
__load_approx_data >"$APPROX_DATA_FILE"
|
|
export APPROX_DATA_FILE
|
|
fi
|
|
if [ -z "${WEEKLY_DATA_FILE:-}" ]; then
|
|
WEEKLY_DATA_FILE=$(mktemp)
|
|
__load_weeks >"$WEEKLY_DATA_FILE"
|
|
export WEEKLY_DATA_FILE
|
|
fi
|
|
|
|
if [ "${1:-}" = "--day" ]; then
|
|
DISPLAY_DATE="$2"
|
|
echo "Jumping to day $DISPLAY_DATE!"
|
|
selection=$(
|
|
__show_day |
|
|
$FZF \
|
|
--reverse \
|
|
--ansi \
|
|
--no-sort \
|
|
--no-input \
|
|
--delimiter='|' \
|
|
--with-nth='{2}' \
|
|
--accept-nth='{1}' \
|
|
--bind="backspace:first+accept"
|
|
)
|
|
if [ -n "$selection" ]; then
|
|
fpath="$ROOT/$selection"
|
|
fi
|
|
fi
|
|
|
|
if [ "${1:-}" = "--date" ]; then
|
|
DISPLAY_DATE="$2"
|
|
echo "Jumping to date $2!"
|
|
fi
|
|
DISPLAY_DATE=${DISPLAY_DATE:-today}
|
|
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=$( (
|
|
cat "$APPROX_DATA_FILE"
|
|
yes " " | head -n 50
|
|
__list
|
|
) |
|
|
$FZF \
|
|
--tac \
|
|
--no-sort \
|
|
--no-hscroll \
|
|
--ellipsis='' \
|
|
--delimiter='|' \
|
|
--with-nth='{4}' \
|
|
--accept-nth=1,2 \
|
|
--no-info \
|
|
--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
|
|
|
|
sign=$(echo "$selection" | cut -d '|' -f 1)
|
|
startdate=$(echo "$selection" | cut -d '|' -f 2)
|
|
if [ "$sign" = "~" ]; then
|
|
exec $0 --date "$startdate"
|
|
else
|
|
exec $0 --day "$startdate"
|
|
fi
|
|
echo "Going to end..."
|
|
echo "$selection"
|
|
echo "STOPPING NOW"
|