Last active
February 6, 2023 23:38
-
-
Save soraxas/b25896f177f883a889a0763c8f593884 to your computer and use it in GitHub Desktop.
script:Taskwarrior wrapper for intelligently parses datetime format (due, scheduled, etc.) in human language.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# By soraxas | |
# This file shall be the wrapper for taskwarrior | |
# Do something like: | |
# alias task="taskwarrior-datetime-parser-wrapper" | |
# argunments that contain datetime format | |
TIME_FORMAT="(^|\W)(until|wait|due|scheduled):" | |
TASK="$(which task)" | |
if [ -z "$TASK" ]; then | |
echo "Binary task not found!" | |
exit 1 | |
fi | |
# check if any argunment matches it | |
if ! echo "$@" | grep -qP "$TIME_FORMAT"; then | |
# no date format in args. | |
"$TASK" "$@" | |
exit $? | |
fi | |
# use python wrapper to intelligently parse datetime | |
# The reason to firt use a bash script to check is because | |
# python has a slow startup time. Which would slow down even | |
# the very basic command without any args. | |
# Therefore, this method ensures that python process is called | |
# only when it is necessary (i.e. when datetime format presents) | |
# and needs potential parsing. | |
PYTHON="$(which python3)" | |
# embed the python script here to avoid having multiple files. | |
"$PYTHON" -c ' | |
import sys | |
import datetime | |
import dateutil.parser | |
import subprocess | |
def parse_with_dateutil(inputs, ensure_future=True): | |
# use dateutil to intelligently parse datetime. | |
parser = dateutil.parser.parser() | |
try: | |
out = parser.parse(inputs) | |
if out.hour == 0 and out.minute == 0: | |
# skip adding time if its the default 00:00 | |
# DATE_FORMAT = "YYYY-MM-DD" | |
DATEUTIL_FORMAT = "%Y-%m-%d" | |
else: | |
# DATE_FORMAT = "YYYY-MM-DDThh:mm" | |
DATEUTIL_FORMAT = "%Y-%m-%dT%H:%M%z" | |
except ValueError: | |
# dateutil couldnt understand it. Probably is TWs builtin special date | |
return None | |
if ensure_future: | |
# ensure the target is in the future | |
now = datetime.datetime.now() | |
if now > out: | |
# check that if user had omitted some settings, make the default to be the | |
# immediate next instance of the given ambigious time. | |
user_provided = parser._parse(inputs)[0] | |
if getattr(user_provided, "day") is None: | |
out = out + dateutil.relativedelta.relativedelta(days=1) | |
elif getattr(user_provided, "month") is None: | |
out = out + dateutil.relativedelta.relativedelta(months=1) | |
elif getattr(user_provided, "year") is None: | |
out = out + dateutil.relativedelta.relativedelta(years=1) | |
return out.strftime(DATEUTIL_FORMAT) | |
class TWCommandline: | |
def __init__(self, argv): | |
"""This class is for easy editing argv.""" | |
self.argv = [] | |
for arg in argv[1:]: # first arg is this script | |
# try different way to separatethe arg | |
for sep in ("=", ":"): | |
if len(arg.split(sep)) == 2: | |
_tmp = arg.split(sep) | |
self.argv.append([_tmp[0], sep, _tmp[1]]) | |
break | |
else: # add the original argunment | |
self.argv.append(arg) | |
def build_cmd(self): | |
return ["".join(a) if isinstance(a, list) else a for a in self.argv] | |
twc = TWCommandline(sys.argv) | |
# dont do any modification if a custom dateformat is used | |
if not any(arg[0] == "rc.dateformat" for arg in twc.argv): | |
# else, use a dateutil-powered parser. | |
timeformat = ("until", "wait", "due", "scheduled") | |
for arg in twc.argv: | |
if arg[0] in timeformat: | |
result = parse_with_dateutil(arg[2]) | |
if result is not None: | |
# notify user of the auto-parsing | |
print("> Auto-converted `{}:{}` -> `{}:{}`".format( | |
arg[0], arg[2], arg[0], result | |
)) | |
# apply new parsed datetime | |
arg[2] = result | |
exit(subprocess.run(["'"$TASK"'"] + twc.build_cmd()).returncode) | |
' $@ | |
exit $? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment