aboutsummaryrefslogtreecommitdiff
path: root/scripts/orgagenda.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/orgagenda.sh')
-rwxr-xr-xscripts/orgagenda.sh98
1 files changed, 98 insertions, 0 deletions
diff --git a/scripts/orgagenda.sh b/scripts/orgagenda.sh
new file mode 100755
index 0000000..9f46778
--- /dev/null
+++ b/scripts/orgagenda.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env sh
+
+set -eu -o pipefail
+
+CONFIG_ORG_DIRECTORY=${CONFIG_ORG_DIRECTORY:-"$HOME/nixos/extras/notes"}
+
+datefmt='%Y-%m-%d'
+datetimefmt='%Y-%m-%d %H:%M:%S'
+
+weekdaynum() { echo "$(($(date -d "$1" +%u) % 7))"; }
+
+today=$(date "+$datefmt")
+weekincrement="${1:-0}"
+target=$(date -d "$weekincrement weeks" "+$datefmt")
+weekstart=$(date -d "$target -$(weekdaynum "$target") days" "+$datefmt")
+nextweekstart=$(date -d "$target -$(weekdaynum "$target") days +1 week" "+$datefmt")
+
+fetch_schedule() {
+ # TODO: Exclude DONE tasks
+ rg -i -g '**/*.org' --vimgrep --multiline \
+ '^\*+\s+(?<heading>.+)\n(^[^*]*\n)*^((?<type>SCHEDULED|DEADLINE)\s*:)?\s*<(?<date>[^>]*)>(--<(?<enddate>[^>]*)>)?' \
+ --replace '§$heading§$type§$date§$enddate' \
+ "$CONFIG_ORG_DIRECTORY" \
+ | sed -E 's/:[0-9]+:[0-9]+://'
+}
+
+# :: Date -> Date
+parse_start_date() {
+ echo "$1" | sed -E 's/^([0-9]+-[0-9]+-[0-9]+)\s*.*/\1/'
+}
+
+# :: ScheduleType -> Date -> End Date -> [Date]
+parse_date_range() {
+ [ -z "$2" ] && return 0
+ parsed_date=$(parse_start_date "$2")
+ if [ "$1" = "DEADLINE" ]; then
+ for i in $(seq 1 2); do
+ local d=$(date -d "$parsed_date -$i days" "+$datefmt" || true)
+ if [ "$d" \> "$today" ] || [ "$d" = "$today" ]; then echo "$d"; fi
+ done
+ date -d "$parsed_date" "+$datefmt" || true
+ else
+ # TODO: Parse end date
+ # TODO: Parse repeat syntax +x as well
+ date -d "$parsed_date" "+$datefmt" || true
+ fi
+}
+
+date_between() {
+ ([ "$1" \> "$2" ] || [ "$1" = "$2" ]) && [ "$1" \< "$3" ]
+}
+
+weeks_events() {
+ fetch_schedule | while IFS=§ read file heading scheduletype original_date end_date; do
+ parse_date_range "$scheduletype" "$original_date" "$end_date" | while IFS= read applied_date; do
+ day_of_week=$(date -d "$applied_date" +%A 2>/dev/null || true)
+ if ! [ -z "$applied_date" ] && (date_between "$applied_date" "$weekstart" "$nextweekstart"); then
+ parsed_date="$(parse_start_date "$original_date")"
+ echo -e "$day_of_week§$heading§$scheduletype§$original_date§$parsed_date§$applied_date"
+ fi
+ done
+ done
+}
+
+date_from_day() {
+ date -d "$weekstart +$(weekdaynum "$1") days" +"$datefmt";
+}
+
+relative_date_diff() {
+ start_sec=$(date -d "$1" +%s)
+ end_sec=$(date -d "$2" +%s)
+ diff=$((end_sec - start_sec))
+ days=$((diff / 86400))
+ if [ $diff = 0 ]; then echo "today"
+ elif [ $diff -gt 0 ]; then echo "in $days days"
+ else echo "$((days * -1)) days ago"
+ fi
+}
+
+events=$(weeks_events)
+cols=$(tput cols)
+
+days_of_week="Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
+
+for day_of_week in ${days_of_week}; do
+ echo -e "\033[38;5;73m${day_of_week} \033[1m($(date_from_day "$day_of_week"))\033[0m"
+ (echo "$events" | grep "^$day_of_week" || true) | \
+ while IFS=§ read _ heading scheduletype original_date real_date date; do
+ eventstyle=""
+ if [ "$scheduletype" = "DEADLINE" ]; then
+ eventstyle=$([ "$date" = "$real_date" ] \
+ && echo "\033[38;5;160m" \
+ || echo "\033[38;5;172m")
+ fi
+ printf "\033[38;5;243m%${cols}s\033[0m" "($original_date) "
+ echo -e "\r ${eventstyle}\033[1m${heading}\033[0m ($(relative_date_diff "$today" "$real_date"))"
+ done
+done