awk based
This commit is contained in:
		
							
								
								
									
										550
									
								
								fab
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										550
									
								
								fab
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,550 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
set -eu
 | 
			
		||||
 | 
			
		||||
# Color support
 | 
			
		||||
GREEN=$(printf '\033[1;32m')
 | 
			
		||||
RED=$(printf '\033[1;31m')
 | 
			
		||||
WHITE=$(printf '\033[1;97m')
 | 
			
		||||
FAINT=$(printf '\033[2m')
 | 
			
		||||
OFF=$(printf '\033[m')
 | 
			
		||||
 | 
			
		||||
# Read configuration
 | 
			
		||||
# shellcheck source=/dev/null
 | 
			
		||||
. "$HOME/.config/fzf-awk-board/config"
 | 
			
		||||
if [ -z "$ROOT" ] || [ -z "$SYNC_CMD" ] || [ -z "$COLLECTION_LABELS" ]; then
 | 
			
		||||
  echo "Failed to get configuration."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
__vtodopriority() {
 | 
			
		||||
  python3 -c '
 | 
			
		||||
import sys
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from icalendar.cal import Todo
 | 
			
		||||
 | 
			
		||||
if not len(sys.argv) == 3:
 | 
			
		||||
    print("Pass ical file as first argument!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
increase = 1 if sys.argv[2] == "1" else -1
 | 
			
		||||
 | 
			
		||||
with open(sys.argv[1], "r") as f:
 | 
			
		||||
    try:
 | 
			
		||||
        ical = Todo.from_ical(f.read())
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"Failed to read vjournal file: {e}", file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
tlist = [component for component in ical.walk("VTODO")]
 | 
			
		||||
if len(tlist) == 0:
 | 
			
		||||
    print("ical file is not a VTODO", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
t = tlist[0]
 | 
			
		||||
 | 
			
		||||
# Update ical
 | 
			
		||||
priority = t.pop("PRIORITY")
 | 
			
		||||
priority = (int(priority) if priority else 0) + increase
 | 
			
		||||
priority = 0 if priority < 0 else 9 if priority > 9 else priority
 | 
			
		||||
t["PRIORITY"] = priority
 | 
			
		||||
 | 
			
		||||
# Print
 | 
			
		||||
print(ical.to_ical().decode().replace("\r\n", "\n"))
 | 
			
		||||
' "$@"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__vtodotogglecompleted() {
 | 
			
		||||
  python3 -c '
 | 
			
		||||
import sys
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from icalendar.cal import Todo
 | 
			
		||||
from icalendar.prop import vDDDTypes
 | 
			
		||||
 | 
			
		||||
if not len(sys.argv) == 2:
 | 
			
		||||
    print("Pass ical file as first argument!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
with open(sys.argv[1], "r") as f:
 | 
			
		||||
    try:
 | 
			
		||||
        ical = Todo.from_ical(f.read())
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"Failed to read vjournal file: {e}", file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
tlist = [component for component in ical.walk("VTODO")]
 | 
			
		||||
if len(tlist) == 0:
 | 
			
		||||
    print("ical file is not a VTODO", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
t = tlist[0]
 | 
			
		||||
 | 
			
		||||
# Update ical
 | 
			
		||||
if t.has_key("STATUS") and t["STATUS"] == "COMPLETED":
 | 
			
		||||
  # Mark as not completed
 | 
			
		||||
  t["STATUS"] = "NEEDS-ACTION"
 | 
			
		||||
  t["PERCENT-COMPLETE"] = 0
 | 
			
		||||
  if t.has_key("COMPLETED"): t.pop("COMPLETED")
 | 
			
		||||
else:
 | 
			
		||||
  t["STATUS"] = "COMPLETED"
 | 
			
		||||
  t["PERCENT-COMPLETE"] = 100
 | 
			
		||||
  t["COMPLETED"] = vDDDTypes(datetime.utcnow())
 | 
			
		||||
 | 
			
		||||
# Print
 | 
			
		||||
print(ical.to_ical().decode().replace("\r\n", "\n"))
 | 
			
		||||
' "$@"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__vicalnew() {
 | 
			
		||||
  python3 -c '
 | 
			
		||||
import sys
 | 
			
		||||
from datetime import date, datetime
 | 
			
		||||
from icalendar.cal import Calendar, Journal, Todo
 | 
			
		||||
from icalendar.prop import vDDDTypes
 | 
			
		||||
 | 
			
		||||
if not len(sys.argv) == 2:
 | 
			
		||||
    print("Pass UID as first argument!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
UID = sys.argv[1]
 | 
			
		||||
 | 
			
		||||
start = None
 | 
			
		||||
due = None
 | 
			
		||||
line = sys.stdin.readline().strip()
 | 
			
		||||
if line[:6] == "::: |>":
 | 
			
		||||
    start = datetime.utcnow().date()
 | 
			
		||||
    line = sys.stdin.readline().strip()
 | 
			
		||||
 | 
			
		||||
if line[:6] == "::: <|":
 | 
			
		||||
    lst = line.split(" ")
 | 
			
		||||
    due = True
 | 
			
		||||
    if len(lst) >= 3:
 | 
			
		||||
      try:
 | 
			
		||||
        duedate = datetime.strptime(lst[2], "%Y-%m-%d").date()
 | 
			
		||||
        due = duedate
 | 
			
		||||
      except Exception as e:
 | 
			
		||||
        pass
 | 
			
		||||
    line = sys.stdin.readline().strip()
 | 
			
		||||
 | 
			
		||||
if not line[:2] == "# ":
 | 
			
		||||
    print("Error: Summary line is corrupt!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
summary = line[2:]
 | 
			
		||||
 | 
			
		||||
line = sys.stdin.readline().strip()
 | 
			
		||||
if not line[:2] == "> " and not line == ">":
 | 
			
		||||
    categories = []
 | 
			
		||||
else:
 | 
			
		||||
    categories = line[2:].split(",")
 | 
			
		||||
    line = sys.stdin.readline().strip()
 | 
			
		||||
 | 
			
		||||
if not line == "":
 | 
			
		||||
    print("Error: Missing separating line!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
description = sys.stdin.read()
 | 
			
		||||
 | 
			
		||||
# Create ical
 | 
			
		||||
now = datetime.utcnow()
 | 
			
		||||
ical = Calendar()
 | 
			
		||||
if due:
 | 
			
		||||
    o = Todo()
 | 
			
		||||
 | 
			
		||||
    # The following are REQUIRED, but MUST NOT occur more than once.
 | 
			
		||||
    # dtstamp / uid /
 | 
			
		||||
    o.DTSTAMP = now
 | 
			
		||||
    o["UID"] = UID
 | 
			
		||||
 | 
			
		||||
    # The following are OPTIONAL, but MUST NOT occur more than once.
 | 
			
		||||
    # class / completed / created / description / dtstart / geo / last-mod /
 | 
			
		||||
    # location / organizer / percent / priority / recurid / seq / status /
 | 
			
		||||
    # summary / url /
 | 
			
		||||
    o["CLASS"] = "PRIVATE"
 | 
			
		||||
    o["CREATED"] = vDDDTypes(now)
 | 
			
		||||
    o["DESCRIPTION"] = description.strip()
 | 
			
		||||
    o.LAST_MODIFIED = now
 | 
			
		||||
    o["PRIORITY"] = 0
 | 
			
		||||
    o["SEQUENCE"] = 0
 | 
			
		||||
    o["STATUS"] = "NEEDS-ACTION"
 | 
			
		||||
    o["SUMMARY"] = summary
 | 
			
		||||
 | 
			
		||||
    # The following is OPTIONAL, but SHOULD NOT occur more than once.
 | 
			
		||||
    # rrule /
 | 
			
		||||
 | 
			
		||||
    # Either "due" or "duration" MAY appear in a "todoprop", but "due" and
 | 
			
		||||
    # "duration" MUST NOT occur in the same "todoprop". If "duration" appear in
 | 
			
		||||
    # a "todoprop", then "dtstart" MUST also appear in the same "todoprop".
 | 
			
		||||
    # due / duration /
 | 
			
		||||
    if isinstance(due, date):
 | 
			
		||||
      o.DUE = due
 | 
			
		||||
 | 
			
		||||
    # The following are OPTIONAL, and MAY occur more than once.
 | 
			
		||||
    # attach / attendee / categories / comment / contact / exdate / rstatus /
 | 
			
		||||
    # related / resources / rdate / x-prop / iana-prop
 | 
			
		||||
    o.categories = categories
 | 
			
		||||
 | 
			
		||||
else:
 | 
			
		||||
    o = Journal()
 | 
			
		||||
    # The following are REQUIRED, but MUST NOT occur more than once.
 | 
			
		||||
    # dtstamp / uid /
 | 
			
		||||
    o.DTSTAMP = now
 | 
			
		||||
    o["UID"] = UID
 | 
			
		||||
    
 | 
			
		||||
    # The following are OPTIONAL, but MUST NOT occur more than once.
 | 
			
		||||
    # class / created / dtstart / last-mod / organizer / recurid / seq / status
 | 
			
		||||
    # / summary / url /
 | 
			
		||||
    o["CLASS"] = "PRIVATE"
 | 
			
		||||
    o["CREATED"] = vDDDTypes(now)
 | 
			
		||||
    o.DTSTART = start
 | 
			
		||||
    o.LAST_MODIFIED = now
 | 
			
		||||
    o["SEQUENCE"] = 0
 | 
			
		||||
    o["STATUS"] = "FINAL"
 | 
			
		||||
    o["SUMMARY"] = summary
 | 
			
		||||
 | 
			
		||||
    # The following is OPTIONAL, but SHOULD NOT occur more than once.
 | 
			
		||||
    # rrule /
 | 
			
		||||
    
 | 
			
		||||
    # The following are OPTIONAL, and MAY occur more than once.
 | 
			
		||||
    # attach / attendee / categories / comment / contact / description / exdate
 | 
			
		||||
    # / related / rdate / rstatus / x-prop / iana-prop
 | 
			
		||||
    o.categories = categories
 | 
			
		||||
    o["DESCRIPTION"] = description.strip()
 | 
			
		||||
 | 
			
		||||
ical.add_component(o)
 | 
			
		||||
 | 
			
		||||
ical["PRODID"] = "fzf-vjour/basic"
 | 
			
		||||
ical["VERSION"] = "2.0"
 | 
			
		||||
 | 
			
		||||
# Print
 | 
			
		||||
print(ical.to_ical().decode().replace("\r\n", "\n"))' "$@"
 | 
			
		||||
}
 | 
			
		||||
__icalupdate() {
 | 
			
		||||
  python3 -c '
 | 
			
		||||
import sys
 | 
			
		||||
from datetime import date, datetime
 | 
			
		||||
from icalendar.cal import Calendar, Todo
 | 
			
		||||
 | 
			
		||||
if not len(sys.argv) == 2:
 | 
			
		||||
    print("Pass ical file as first argument!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
with open(sys.argv[1], "r") as f:
 | 
			
		||||
    try:
 | 
			
		||||
        ical = Calendar.from_ical(f.read())
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"Failed to read ical file: {e}", file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
olist = [component for component in ical.walk(select=lambda c:c.name in ["VJOURNAL", "VTODO"])]
 | 
			
		||||
if len(olist) == 0:
 | 
			
		||||
    sys.exit(0)
 | 
			
		||||
 | 
			
		||||
o = olist[0]
 | 
			
		||||
 | 
			
		||||
line = sys.stdin.readline().strip()
 | 
			
		||||
due = None
 | 
			
		||||
if isinstance(o, Todo):
 | 
			
		||||
    if not line[:6] == "::: <|":
 | 
			
		||||
        print("Error: Due date line is corrupt!", file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    lst = line.split(" ")
 | 
			
		||||
    due = True
 | 
			
		||||
    if len(lst) >= 3:
 | 
			
		||||
      try:
 | 
			
		||||
        duedate = datetime.strptime(lst[2], "%Y-%m-%d").date()
 | 
			
		||||
        due = duedate
 | 
			
		||||
      except Exception as e:
 | 
			
		||||
        pass
 | 
			
		||||
    line = sys.stdin.readline().strip()
 | 
			
		||||
 | 
			
		||||
if not line[:2] == "# ":
 | 
			
		||||
    print("Error: Summary line is corrupt!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
summary = line[2:]
 | 
			
		||||
 | 
			
		||||
line = sys.stdin.readline().strip()
 | 
			
		||||
if not line[:2] == "> " and not line == ">":
 | 
			
		||||
    categories = []
 | 
			
		||||
else:
 | 
			
		||||
    categories = line[2:].split(",")
 | 
			
		||||
    line = sys.stdin.readline().strip()
 | 
			
		||||
 | 
			
		||||
if not line == "":
 | 
			
		||||
    print("Error: Missing separating line!", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
description = sys.stdin.read()
 | 
			
		||||
 | 
			
		||||
# Update ical
 | 
			
		||||
if due:
 | 
			
		||||
    if isinstance(due, date):
 | 
			
		||||
        o.DUE = due 
 | 
			
		||||
    elif "DUE" in o.keys():
 | 
			
		||||
        o.pop("DUE")
 | 
			
		||||
o["SUMMARY"] = summary
 | 
			
		||||
o.categories = categories
 | 
			
		||||
o["DESCRIPTION"] = description.strip()
 | 
			
		||||
o.LAST_MODIFIED = datetime.utcnow()
 | 
			
		||||
seq = o["SEQUENCE"] if "SEQUENCE" in o.keys() else 0
 | 
			
		||||
o["SEQUENCE"] = seq + 1
 | 
			
		||||
 | 
			
		||||
# Print
 | 
			
		||||
print(ical.to_ical().decode().replace("\r\n", "\n"))
 | 
			
		||||
' "$@"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__ical2json() {
 | 
			
		||||
  python3 -c '
 | 
			
		||||
import sys
 | 
			
		||||
import json
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from zoneinfo import ZoneInfo
 | 
			
		||||
from icalendar.cal import Calendar, Todo
 | 
			
		||||
 | 
			
		||||
input_data = sys.stdin.read()
 | 
			
		||||
try:
 | 
			
		||||
    ical = Calendar.from_ical(input_data)
 | 
			
		||||
except Exception as e:
 | 
			
		||||
    print(f"Failed to read ical file: {e}", file=sys.stderr)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
olist = [component for component in ical.walk(select=lambda c:c.name in ["VJOURNAL", "VTODO"])]
 | 
			
		||||
if len(olist) == 0:
 | 
			
		||||
    sys.exit(0)
 | 
			
		||||
 | 
			
		||||
o = olist[0]
 | 
			
		||||
 | 
			
		||||
local_tz = ZoneInfo("localtime")
 | 
			
		||||
data = {
 | 
			
		||||
    "summary": o.get("SUMMARY"),
 | 
			
		||||
    "description": o.get("DESCRIPTION") if "DESCRIPTION" in o.keys() else "",
 | 
			
		||||
    "categories": o.categories,
 | 
			
		||||
    "class": o.get("CLASS"),
 | 
			
		||||
    "created": str(o.DTSTAMP.astimezone(local_tz)) if o.DTSTAMP else "",
 | 
			
		||||
    "last_modified": str(o.LAST_MODIFIED.astimezone(local_tz)) if o.LAST_MODIFIED else "",
 | 
			
		||||
    "start": str(
 | 
			
		||||
        o.DTSTART.astimezone(local_tz)
 | 
			
		||||
        if isinstance(o.DTSTART, datetime)
 | 
			
		||||
        else o.DTSTART or ""
 | 
			
		||||
    ),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if isinstance(o, Todo):
 | 
			
		||||
    data["due"] = str(o.DUE) if o.DUE else ""
 | 
			
		||||
 | 
			
		||||
print(json.dumps(data))'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__lines() {
 | 
			
		||||
  find "$ROOT" -type f -name '*.ics' -print0 | xargs -0 -P 0 \
 | 
			
		||||
    awk -f "./src/list.awk" \
 | 
			
		||||
    -v collection_labels="$COLLECTION_LABELS" \
 | 
			
		||||
    -v flag_open="🔲" \
 | 
			
		||||
    -v flag_completed="✅" \
 | 
			
		||||
    -v flag_journal="📘" \
 | 
			
		||||
    -v flag_note="🗒️" |
 | 
			
		||||
    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 <selection>               Generate preview"
 | 
			
		||||
  echo "  --delete <selection>                Delete selected entry"
 | 
			
		||||
  echo "  --decrease-priority <selection>     Decrease priority of selected task"
 | 
			
		||||
  echo "  --increase-priority <selection>     Increase priority of selected task"
 | 
			
		||||
  echo "  --toggle-completed <selection>      Toggle completion flag of task"
 | 
			
		||||
  exit
 | 
			
		||||
fi
 | 
			
		||||
# Command line arguments to be self-contained
 | 
			
		||||
# Generate preview of file from selection
 | 
			
		||||
if [ "${1:-}" = "--preview" ]; then
 | 
			
		||||
  vjfile=$(__filepath_from_selection "$2")
 | 
			
		||||
  __ical2json <"$vjfile" | jq -r ".description" | batcat --color=always --style=numbers --language=md
 | 
			
		||||
  exit
 | 
			
		||||
fi
 | 
			
		||||
# Delete file from selection
 | 
			
		||||
if [ "${1:-}" = "--delete" ]; then
 | 
			
		||||
  vjfile=$(__filepath_from_selection "$2")
 | 
			
		||||
  rm -i "$vjfile"
 | 
			
		||||
fi
 | 
			
		||||
# Generate new entry
 | 
			
		||||
if [ "${1:-}" = "--new" ]; then
 | 
			
		||||
  collection=$(echo "$LABLES" | fzf \
 | 
			
		||||
    --margin 20% \
 | 
			
		||||
    --prompt="Select collection> ")
 | 
			
		||||
  file=""
 | 
			
		||||
  while [ -f "$file" ] || [ -z "$file" ]; do
 | 
			
		||||
    uuid=$(uuidgen)
 | 
			
		||||
    file=$(__filepath_from_selection "$collection /$uuid.ics")
 | 
			
		||||
  done
 | 
			
		||||
  tmpmd=$(mktemp --suffix='.md')
 | 
			
		||||
  tmpsha="$tmpmd.sha"
 | 
			
		||||
  {
 | 
			
		||||
    echo "::: |> <!-- keep this line to associate the entry to _today_ -->"
 | 
			
		||||
    echo "::: <| <!-- specify the due date for to-dos, can be empty -->"
 | 
			
		||||
    echo "# <!-- write summary here -->"
 | 
			
		||||
    echo "> <!-- comma-separated list of categories -->"
 | 
			
		||||
    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"
 | 
			
		||||
    tmpferr="$tmpmd.err"
 | 
			
		||||
    if __vicalnew "$uuid" <"$tmpmd" >"$tmpfile" 2>"$tmpferr"; then
 | 
			
		||||
      mv "$tmpfile" "$file"
 | 
			
		||||
    else
 | 
			
		||||
      rm "$tmpfile"
 | 
			
		||||
      less "$tmpferr"
 | 
			
		||||
    fi
 | 
			
		||||
    rm "$tmpferr"
 | 
			
		||||
  fi
 | 
			
		||||
  rm "$tmpmd" "$tmpsha"
 | 
			
		||||
fi
 | 
			
		||||
# Toggle completed flag
 | 
			
		||||
if [ "${1:-}" = "--toggle-completed" ]; then
 | 
			
		||||
  vtfile=$(__filepath_from_selection "$2")
 | 
			
		||||
  vtfile_tmp=$(mktemp)
 | 
			
		||||
  __vtodotogglecompleted "$vtfile" >"$vtfile_tmp" && mv "$vtfile_tmp" "$vtfile" || rm "$vtfile_tmp"
 | 
			
		||||
fi
 | 
			
		||||
# Increase priority
 | 
			
		||||
if [ "${1:-}" = "--increase-priority" ]; then
 | 
			
		||||
  vtfile=$(__filepath_from_selection "$2")
 | 
			
		||||
  vtfile_tmp=$(mktemp)
 | 
			
		||||
  __vtodopriority "$vtfile" "1" >"$vtfile_tmp" && mv "$vtfile_tmp" "$vtfile" || rm "$vtfile_tmp"
 | 
			
		||||
fi
 | 
			
		||||
# Decrease priority
 | 
			
		||||
if [ "${1:-}" = "--decrease-priority" ]; then
 | 
			
		||||
  vtfile=$(__filepath_from_selection "$2")
 | 
			
		||||
  vtfile_tmp=$(mktemp)
 | 
			
		||||
  __vtodopriority "$vtfile" "-1" >"$vtfile_tmp" && mv "$vtfile_tmp" "$vtfile" || rm "$vtfile_tmp"
 | 
			
		||||
fi
 | 
			
		||||
if [ "${1:-}" = "--reload" ]; then
 | 
			
		||||
  __lines
 | 
			
		||||
  exit
 | 
			
		||||
fi
 | 
			
		||||
if [ "${1:-}" = "--search-line" ]; then
 | 
			
		||||
  __filepath_to_searchline "$2"
 | 
			
		||||
  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)"
 | 
			
		||||
  #--preview="$0 --preview {}" \
 | 
			
		||||
  #--bind="ctrl-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)" \
 | 
			
		||||
)
 | 
			
		||||
echo "OK"
 | 
			
		||||
if [ -z "$selection" ]; then
 | 
			
		||||
  return 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
file=$(__filepath_from_selection "$selection")
 | 
			
		||||
 | 
			
		||||
if [ ! -f "$file" ]; then
 | 
			
		||||
  echo "ERROR: File '$file' does not exist!"
 | 
			
		||||
  return 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Parse vjournal file and save as json
 | 
			
		||||
filejson=$(mktemp)
 | 
			
		||||
__ical2json <"$file" >"$filejson"
 | 
			
		||||
 | 
			
		||||
# Prepare file to be edited
 | 
			
		||||
filetmp=$(mktemp --suffix='.md')
 | 
			
		||||
filesha="$filetmp.sha"
 | 
			
		||||
if jq -e '.due' "$filejson"; then
 | 
			
		||||
  due=$(jq -r '.due' "$filejson")
 | 
			
		||||
  echo "::: <| $due" >"$filetmp"
 | 
			
		||||
fi
 | 
			
		||||
summary=$(jq -r '.summary' "$filejson")
 | 
			
		||||
categories=$(jq -r '.categories | join(",")' "$filejson")
 | 
			
		||||
{
 | 
			
		||||
  echo "# $summary"
 | 
			
		||||
  echo "> $categories"
 | 
			
		||||
  echo ""
 | 
			
		||||
  jq -r '.description' "$filejson"
 | 
			
		||||
} >>"$filetmp"
 | 
			
		||||
rm "$filejson"
 | 
			
		||||
sha1sum "$filetmp" >"$filesha"
 | 
			
		||||
 | 
			
		||||
# Open in editor
 | 
			
		||||
$EDITOR "$filetmp"
 | 
			
		||||
 | 
			
		||||
# Update only if changes are detected
 | 
			
		||||
if ! sha1sum -c "$filesha" >/dev/null 2>&1; then
 | 
			
		||||
  echo "Uh... chages detected!"
 | 
			
		||||
  vj_file_new="$filetmp.ics"
 | 
			
		||||
  __icalupdate "$file" <"$filetmp" >"$vj_file_new" && mv "$vj_file_new" "$file" || rm "$vj_file_new"
 | 
			
		||||
fi
 | 
			
		||||
rm "$filetmp" "$filesha"
 | 
			
		||||
 | 
			
		||||
exec "$0"
 | 
			
		||||
		Reference in New Issue
	
	Block a user