From 0c742eccd4eacbb12e78704d628ff0fe9af397e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=84min=20Baumeler?= Date: Mon, 2 Jun 2025 09:24:32 +0200 Subject: [PATCH] removed tracking of fzf-vjour --- fzf-vjour | 752 ------------------------------------------------------ 1 file changed, 752 deletions(-) delete mode 100755 fzf-vjour diff --git a/fzf-vjour b/fzf-vjour deleted file mode 100755 index a6f7d9d..0000000 --- a/fzf-vjour +++ /dev/null @@ -1,752 +0,0 @@ -#!/bin/sh - -set -eu - -# Read configuration -# shellcheck source=/dev/null -. "$HOME/.config/fzf-vjour/config" -if [ -z "$ROOT" ] || [ -z "$SYNC_CMD" ] || [ -z "$COLLECTION_LABELS" ]; then - echo "Failed to get configuration." >/dev/tty - exit 1 -fi - -### AWK SCRIPTS -AWK_ALTERTODO=$( - cat <<'EOF' -# Increase/decrease priority, or toggle completed status -# -# If `delta` is specified using `-v`, then the priority value is increased by -# `delta.` If `delta` is unspecified (or equal to 0), then the completeness -# status is toggled. -BEGIN { - FS=":"; - zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1); - delta = delta + 0; # cast as integer -} -/^END:VTODO/ && inside { - # Print sequence and last-modified, if not yet printed - if (!seq) print "SEQUENCE:1"; - if (!lm) print "LAST-MODIFIED:" zulu; - - # Print priority - prio = prio ? prio + delta : 0 + delta; - prio = prio < 0 ? 0 : prio; - prio = prio > 9 ? 9 : prio; - print "PRIORITY:" prio; - - # Print status (toggle if needed) - bit_status = status == "COMPLETED" ? 1 : 0; - bit_toggle = delta ? 0 : 1; - percent = xor(bit_status, bit_toggle) ? 100 : 0; - status = xor(bit_status, bit_toggle) ? "COMPLETED" : "NEEDS-ACTION"; - print "STATUS:" status - print "PERCENT-COMPLETE:" percent - - # print rest - inside = ""; - print $0; - next -} -/^BEGIN:VTODO/ { inside = 1; print; next } -/^SEQUENCE/ && inside { seq = 1; print "SEQUENCE:" $2+1; next } -/^LAST-MODIFIED/ && inside { lm = 1; print "LAST-MODIFIED:" zulu; next } -/^PRIORITY:/ && inside { prio = $2; next } -/^STATUS/ && inside { status = $2; next } -/^PERCENT-COMPLETE/ && inside { next } # ignore, we take STATUS:COMPLETED as reference -{ print } -EOF -) - -AWK_EXPORT=$( - cat <<'EOF' -function getcontent(content_line, prop) -{ - return substr(content_line[prop], index(content_line[prop], ":") + 1); -} - -function storetext_line(content_line, c, prop) -{ - c[prop] = getcontent(content_line, prop); - gsub("\\\\n", "\n", c[prop]); - gsub("\\\\N", "\n", c[prop]); - gsub("\\\\,", ",", c[prop]); - gsub("\\\\;", ";", c[prop]); - gsub("\\\\\\\\", "\\", c[prop]); -} - -BEGIN { FS = "[:;]"; } -/^BEGIN:(VJOURNAL|VTODO)/ { type = $2 } -/^END:/ && $2 == type { exit } -/^(CATEGORIES|DESCRIPTION|SUMMARY|DUE)/ { prop = $1; content_line[prop] = $0; next; } -/^[^ ]/ && prop { prop = ""; next; } -/^ / && prop { content_line[prop] = content_line[prop] substr($0, 2); next; } - -END { - if (!type) { - exit - } - # Process content lines - storetext_line(content_line, c, "CATEGORIES" ); - storetext_line(content_line, c, "DESCRIPTION"); - storetext_line(content_line, c, "SUMMARY" ); - storetext_line(content_line, c, "DUE" ); - # Print - if (c["DUE"]) - print "::: <| " substr(c["DUE"], 1, 4) "-" substr(c["DUE"], 5, 2) "-" substr(c["DUE"], 7, 2); - print "# " c["SUMMARY"]; - print "> " c["CATEGORIES"]; - print ""; - print c["DESCRIPTION"]; -} -EOF -) - -AWK_GET=$( - cat <<'EOF' -# print content of field `field` -BEGIN { FS = ":"; regex = "^" field; } -/^BEGIN:(VJOURNAL|VTODO)/ { type = $2 } -/^END:/ && $2 == type { exit } -$0 ~ field { content = $0; next; } -/^ / && content { content = content substr($0, 2); next; } -/^[^ ]/ && content { exit } -END { - if (!type) { exit } - # Process content line - content = substr(content, index(content, ":") + 1); - gsub("\\\\n", "\n", content); - gsub("\\\\N", "\n", content); - gsub("\\\\,", ",", content); - gsub("\\\\;", ";", content); - gsub("\\\\\\\\", "\\", content); - print content; -} -EOF -) - -AWK_LIST=$( - cat <<'EOF' -# awk script to generate summary line for iCalendar VJOURNAL and VTODO entries -# -# See https://datatracker.ietf.org/doc/html/rfc5545 for the RFC 5545 that -# describes iCalendar, and its syntax - -function getcontent(content_line, prop) -{ - return substr(content_line[prop], index(content_line[prop], ":") + 1); -} - -function storetext_line(content_line, c, prop) -{ - c[prop] = getcontent(content_line, prop); - gsub("\\\\n", " ", c[prop]); - gsub("\\\\N", " ", c[prop]); - gsub("\\\\,", ",", c[prop]); - gsub("\\\\;", ";", c[prop]); - gsub("\\\\\\\\", "\\", c[prop]); - #gsub(" ", "_", c[prop]); -} - -function storeinteger(content_line, c, prop) -{ - c[prop] = getcontent(content_line, prop); - c[prop] = c[prop] ? c[prop] : 0; -} - -function storedatetime(content_line, c, prop) -{ - c[prop] = getcontent(content_line, prop); -} - -function storedate(content_line, c, prop) -{ - c[prop] = substr(getcontent(content_line, prop), 1, 8); -} - -function formatdate(date, today, todaystamp, ts, ts_y, ts_m, ts_d, delta) -{ - ts_y = substr(date, 1, 4); - ts_m = substr(date, 5, 2); - ts_d = substr(date, 7); - ts = mktime(ts_y " " ts_m " " ts_d " 00 00 00"); - delta = (ts - todaystamp) / 86400; - if (delta >= 0 && delta < 1) { - return " today"; - } - if (delta >= 1 && delta < 2) { - return " tomorrow"; - } - if (delta >= 2 && delta < 3) { - return " in two days"; - } - if (delta >= 3 && delta < 4) { - return " in three days"; - } - if (delta < 0 && delta >= -1) { - return " yesterday"; - } - if (delta < -1 && delta >= -2) { - return " two days ago"; - } - if (delta < -2 && delta >= -3) { - return "three days ago"; - } - return " " substr(date, 1, 4) "-" substr(date, 5, 2) "-" substr(date, 7); -} - -BEGIN { - # We require the following variables to be set using -v - # collection_lables: ;-delimited collection=label strings - # flag_open: symbol for open to-dos - # flag_completed: symbol for completed to-dos - # flag_journal: symbol for journal entries - # flag_note: symbol for note entries - - FS = "[:;]"; - # Collections - 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"; - - # For date comparision - today = strftime("%Y%m%d"); - todaystamp = mktime(substr(today, 1, 4) " " substr(today, 5, 2) " " substr(today, 7) " 00 00 00"); -} - -# Reset variables -BEGINFILE { - type = ""; - prop = ""; - delete content_line; - delete c; - -} - -/^BEGIN:(VJOURNAL|VTODO)/ { - type = $2 -} - -/^END:/ && $2 == type { - nextfile -} - -/^(CATEGORIES|DESCRIPTION|PRIORITY|STATUS|SUMMARY|COMPLETED|DUE|DTSTART|DURATION|CREATED|DTSTAMP|LAST-MODIFIED)/ { - prop = $1; - content_line[prop] = $0; - next; -} -/^[^ ]/ && prop { - prop = ""; - next; -} -/^ / && prop { - content_line[prop] = content_line[prop] substr($0, 2); - next; -} - -ENDFILE { - if (!type) { - exit - } - # Process content lines - storetext_line(content_line, c, "CATEGORIES" ); - storetext_line(content_line, c, "DESCRIPTION" ); - storeinteger( content_line, c, "PRIORITY" ); - storetext_line(content_line, c, "STATUS" ); - storetext_line(content_line, c, "SUMMARY" ); - storedatetime( content_line, c, "COMPLETED" ); - storedate( content_line, c, "DUE" ); - storedate( content_line, c, "DTSTART" ); - storedatetime( content_line, c, "DURATION" ); - storedatetime( content_line, c, "CREATED" ); - storedatetime( content_line, c, "DTSTAMP" ); - storedatetime( content_line, c, "LAST-MODIFIED"); - - # Priority field, primarly used for sorting - priotext = ""; - prio = 0; - if (c["PRIORITY"] > 0) - { - priotext = "❗(" c["PRIORITY"] ") "; - prio = 10 - c["PRIORITY"]; - } - - # Last modification/creation time stamp, used for sorting - # LAST-MODIFIED: Optional field for VTODO and VJOURNAL entries, date-time in - # UTC time format - # DTSTAMP: mandatory field in VTODO and VJOURNAL, date-time in UTC time - # format - mod = c["LAST-MODIFIED"] ? c["LAST-MODIFIED"] : c["DTSTAMP"]; - - # Collection name - depth = split(FILENAME, path, "/"); - collection = depth > 1 ? path[depth-1] : ""; - collection = collection in collection2label ? collection2label[collection] : collection; - - # Date field. For VTODO entries, we show the due date, for journal entries, - # the associated date. - datecolor = CYAN; - summarycolor = GREEN; - - if (type == "VTODO") - { - # Either DUE or DURATION may appear. If DURATION appears, then also DTSTART - d = c["DUE"] ? c["DUE"] : - (c["DURATION"] ? c["DTSTART"] " for " c["DURATION"] : ""); - if (d && d <= today && c["STATUS"] != "COMPLETED") - { - datecolor = RED; - summarycolor = RED; - } - } else { - d = c["DTSTART"]; - } - d = d ? formatdate(d, today, todaystamp ts, ts_y, ts_m, ts_d, delta) : " "; - - # flag: - "journal" for VJOURNAL with DTSTART - # - "note" for VJOURNAL without DTSTART - # - "completed" for VTODO with c["STATUS"] == COMPLETED - # - "open" for VTODO with c["STATUS"] != COMPLETED - if (type == "VTODO") - flag = c["STATUS"] == "COMPLETED" ? flag_completed : flag_open; - else - flag = c["DTSTART"] ? flag_journal : flag_note; - - # summary - # c["SUMMARY"] - summary = c["SUMMARY"] ? c["SUMMARY"] : " " - - # categories - categories = c["CATEGORIES"] ? c["CATEGORIES"] : " " - - # filename - # FILENAME - - print prio, - mod, - collection, - datecolor d OFF, - flag, - priotext summarycolor summary OFF, - WHITE categories OFF, - " " FAINT FILENAME OFF; -} -EOF -) - -AWK_NEW=$( - cat <<'EOF' -function escape_categories(str) -{ - gsub("\\\\", "\\\\", str); - gsub(";", "\\\\;", str); -} - -function escape(str) -{ - escape_categories(str) - gsub(",", "\\\\,", str); -} - -function print_fold(nameparam, content, i, s) -{ - i = 74 - length(nameparam); - s = substr(content, 1, i); - print nameparam s; - s = substr(content, i+1, 73); - i = i + 73; - while (s) - { - print " " s; - s = substr(content, i+1, 73); - i = i + 73; - } -} - -BEGIN { - FS=":"; - type = "VJOURNAL"; - zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1); -} -desc { desc = desc "\\n" $0; next; } -{ - if (substr($0, 1, 6) == "::: |>") - { - start = substr(zulu, 1, 8); - getline; - } - if (substr($0, 1, 6) == "::: <|") - { - type = "VTODO" - due = substr($0, 8); - getline; - } - summary = substr($0, 1, 2) != "# " ? "" : substr($0, 3); - getline; - categories = substr($0, 1, 1) != ">" ? "" : substr($0, 3); - getline; # This line should be empty - getline; # First line of description - desc = $0; - next; -} -END { - # Sanitize input - if (due) { - # Use command line `date` for parsing - cmd = "date -d \"" due "\" +\"%Y%m%d\""; - cmd | getline res - due = res ? res : "" - } - escape(summary); - escape(desc); - escape_categories(categories); - - # print ical - print "BEGIN:VCALENDAR"; - print "VERSION:2.0"; - print "CALSCALE:GREGORIAN"; - print "PRODID:-//fab//awk//EN"; - print "BEGIN:" type; - print "DTSTAMP:" zulu; - print "UID:" uid; - print "CLASS:PRIVATE"; - print "CREATED:" zulu; - print "SEQUENCE:1"; - print "LAST-MODIFIED:" zulu; - if (type == "VTODO") - { - print "STATUS:NEEDS-ACTION"; - print "PERCENT-COMPLETE:0"; - if (due) - print "DUE;VALUE=DATE:" due; - } - else - { - print "STATUS:FINAL"; - if (start) - print "DTSTART;VALUE=DATE:" start; - } - if (summary) print_fold("SUMMARY:", summary, i, s); - if (categories) print_fold("CATEGORIES:", categories, i, s); - if (desc) print_fold("DESCRIPTION:", desc, i, s); - print "END:" type; - print "END:VCALENDAR" -} -EOF -) - -AWK_UPDATE=$( - cat <<'EOF' -function getcontent(content_line, prop) -{ - return substr(content_line[prop], index(content_line[prop], ":") + 1); -} - -function escape_categories(str) -{ - gsub("\\\\", "\\\\", str); - gsub(";", "\\\\;", str); -} - -function escape(str) -{ - escape_categories(str) - gsub(",", "\\\\,", str); -} - -function print_fold(nameparam, content, i, s) -{ - i = 74 - length(nameparam); - s = substr(content, 1, i); - print nameparam s; - s = substr(content, i+1, 73); - i = i + 73; - while (s) - { - print " " s; - s = substr(content, i+1, 73); - i = i + 73; - } -} - -BEGIN { - FS=":"; - zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1); -} - -ENDFILE { - if (NR == FNR) - { - # Sanitize input - if (due) { - # Use command line `date` for parsing - cmd = "date -d \"" due "\" +\"%Y%m%d\""; - cmd | getline res - due = res ? res : "" - } - escape(summary); - escape(desc); - escape_categories(categories); - } -} - -NR == FNR && desc { desc = desc "\\n" $0; next; } -NR == FNR { - if (substr($0, 1, 6) == "::: <|") - { - due = substr($0, 8); - getline; - } - summary = substr($0, 1, 2) != "# " ? "" : substr($0, 3); - getline; - categories = substr($0, 1, 1) != ">" ? "" : substr($0, 3); - getline; # This line should be empty - getline; # First line of description - desc = $0; - next; -} - -/^BEGIN:(VJOURNAL|VTODO)/ { type = $2; print; next } -/^X-ALT-DESC/ && type { next } # drop this alternative description -/^ / && type { next } # drop this folded line (the only content with folded lines will be updated) -/^(DUE|SUMMARY|CATEGORIES|DESCRIPTION|LAST-MODIFIED)/ && type { next } # skip for now, we will write updated fields at the end -/^SEQUENCE/ && type { seq = $2; next } # store sequence number and skip -/^END:/ && type == $2 { - seq = seq ? seq + 1 : 1; - print "SEQUENCE:" seq; - print "LAST-MODIFIED:" zulu; - if (due) print "DUE;VALUE=DATE:" due; - print_fold("SUMMARY:", summary, i, s); - print_fold("CATEGORIES:", categories, i, s); - print_fold("DESCRIPTION:", desc, i, s); - type = ""; -} -{ print } -EOF -) -### END OF AWK SCRIPTS - -__lines() { - find "$ROOT" -type f -name '*.ics' -print0 | xargs -0 -P 0 \ - awk \ - -v collection_labels="$COLLECTION_LABELS" \ - -v flag_open="🔲" \ - -v flag_completed="✅" \ - -v flag_journal="📘" \ - -v flag_note="🗒️" \ - "$AWK_LIST" | - sort -g -r | - cut -d ' ' -f 3- -} - -__filepath_from_selection() { - echo "$1" | grep -o ' \{50\}.*$' | xargs -} - -# Program starts here -if [ "${1:-}" = "--help" ]; then - echo "Usage: $0 [OPTION]" - echo "" - echo "You may specify at most one option." - echo " --help Show this help and exit" - echo " --tasks Show tasks only" - echo " --no-tasks Ignore tasks" - echo " --notes Show notes only" - echo " --no-notes Ignore notes" - echo " --journal Show journal only" - echo " --no-journal Ignore journal" - echo " --completed Show completed tasks only" - echo " --no-completed Ignore completed tasks" - echo " --new Create new entry" - echo "" - echo "The following options are for internal use." - echo " --reload Reload list" - echo " --preview Generate preview" - echo " --delete Delete selected entry" - echo " --decrease-priority Decrease priority of selected task" - echo " --increase-priority Increase priority of selected task" - echo " --toggle-completed Toggle completion flag of task" - exit -fi - -# Command line arguments to be self-contained -# Generate preview of file from selection -if [ "${1:-}" = "--preview" ]; then - file=$(__filepath_from_selection "$2") - awk -v field="DESCRIPTION" "$AWK_GET" "$file" | - batcat --color=always --style=numbers --language=md - exit -fi -# Delete file from selection -if [ "${1:-}" = "--delete" ]; then - file=$(__filepath_from_selection "$2") - summary=$(awk -v field="SUMMARY" "$AWK_GET" "$file") - while true; do - printf "Do you want to delete the entry with the title \"%s\"? " "$summary" >/dev/tty - read -r yn - case $yn in - "yes") - rm -v "$file" - break - ;; - "no") - break - ;; - *) - echo "Please answer \"yes\" or \"no\"." >/dev/tty - ;; - esac - done -fi -# Generate new entry -if [ "${1:-}" = "--new" ]; then - label=$(printf "%s" "$COLLECTION_LABELS" | - awk 'BEGIN { FS="="; RS=";"; } {print $2}' | - fzf \ - --margin 20% \ - --prompt="Select collection> ") - - collection=$(printf "%s" "$COLLECTION_LABELS" | - awk -v label="$label" 'BEGIN { FS="="; RS=";"; } $2 == label {print $1}') - file="" - while [ -f "$file" ] || [ -z "$file" ]; do - uuid=$(uuidgen) - file="$ROOT/$collection/$uuid.ics" - done - tmpmd=$(mktemp --suffix='.md') - tmpsha="$tmpmd.sha" - { - echo "::: |> " - echo "::: <| " - echo "# " - echo "> " - echo "" - } >"$tmpmd" - sha1sum "$tmpmd" >"$tmpsha" - - # Open in editor - $EDITOR "$tmpmd" >/dev/tty - - # Update if changes are detected - if ! sha1sum -c "$tmpsha" >/dev/null 2>&1; then - tmpfile="$tmpmd.ics" - awk -v uid="$uuid" "$AWK_NEW" "$tmpmd" >"$tmpfile" - mv "$tmpfile" "$file" - fi - rm "$tmpmd" "$tmpsha" -fi -# Toggle completed flag -if [ "${1:-}" = "--toggle-completed" ]; then - file=$(__filepath_from_selection "$2") - tmpfile=$(mktemp) - awk "$AWK_ALTERTODO" "$file" >"$tmpfile" - mv "$tmpfile" "$file" -fi -# Increase priority -if [ "${1:-}" = "--increase-priority" ]; then - file=$(__filepath_from_selection "$2") - tmpfile=$(mktemp) - awk -v delta="1" "$AWK_ALTERTODO" "$file" >"$tmpfile" - mv "$tmpfile" "$file" -fi -# Decrease priority -if [ "${1:-}" = "--decrease-priority" ]; then - file=$(__filepath_from_selection "$2") - tmpfile=$(mktemp) - awk -v delta="-1" "$AWK_ALTERTODO" "$file" >"$tmpfile" - mv "$tmpfile" "$file" -fi -if [ "${1:-}" = "--reload" ]; then - __lines - exit -fi - -query="${FZF_QUERY:-}" -if [ "${1:-}" = "--no-completed" ]; then - query="!✅" -fi -if [ "${1:-}" = "--completed" ]; then - query="✅" -fi -if [ "${1:-}" = "--tasks" ]; then - query="✅ | 🔲" -fi -if [ "${1:-}" = "--no-tasks" ]; then - query="!✅ !🔲" -fi -if [ "${1:-}" = "--notes" ]; then - query="🗒️" -fi -if [ "${1:-}" = "--no-notes" ]; then - query="!🗒️" -fi -if [ "${1:-}" = "--journal" ]; then - query="📘" -fi -if [ "${1:-}" = "--no-journal" ]; then - query="!📘" -fi -if [ -z "$query" ]; then - query="!✅" -fi -query=$(echo "$query" | sed 's/ *$//g') - -selection=$( - __lines | fzf --ansi \ - --query="$query " \ - --no-sort \ - --no-hscroll \ - --ellipsis='' \ - --preview="$0 --preview {}" \ - --bind="ctrl-r:reload-sync($0 --reload)" \ - --bind="ctrl-alt-d:become($0 --delete {})" \ - --bind="ctrl-x:become($0 --toggle-completed {})" \ - --bind="alt-up:become($0 --increase-priority {})" \ - --bind="alt-down:become($0 --decrease-priority {})" \ - --bind="ctrl-n:become($0 --new)" \ - --bind="alt-0:change-query(!✅)" \ - --bind="alt-1:change-query(📘)" \ - --bind="alt-2:change-query(🗒️)" \ - --bind="alt-3:change-query(✅ | 🔲)" \ - --bind="ctrl-s:execute($SYNC_CMD)" -) -if [ -z "$selection" ]; then - return 0 -fi - -file=$(__filepath_from_selection "$selection") - -if [ ! -f "$file" ]; then - echo "ERROR: File '$file' does not exist!" >/dev/tty - return 1 -fi - -# Prepare file to be edited -filetmp=$(mktemp --suffix='.md') -filesha="$filetmp.sha" -awk "$AWK_EXPORT" "$file" >"$filetmp" -sha1sum "$filetmp" >"$filesha" - -# Open in editor -$EDITOR "$filetmp" >/dev/tty - -# Update only if changes are detected -if ! sha1sum -c "$filesha" >/dev/null 2>&1; then - echo "Uh... chages detected!" >/dev/tty - file_new="$filetmp.ics" - awk "$AWK_UPDATE" "$filetmp" "$file" >"$file_new" - mv "$file_new" "$file" -fi -rm "$filetmp" "$filesha" - -exec "$0"