Marty Oehme
aefce1c498
The beginning of what I hope can be a useful integration: send mails to taskwarrior as tasks and open the corresponding mail from tasks in taskwarrior. To make a task out of an e-mail, in neomutt, simply press `t` when the mail is selected or opened. It will create an automatic task in taskwarrior with the description "Reply to [mail] by [sender]" and tag it as mail. If you press `T` instead, you can give the task your own description and tags. In taskwarrior, you can simply `t open <taskid>` on a task that came from neomutt to show the message content on the command line (using notmuch). This is still a bit rudimentary and I would like an improved display, but it works for now.
100 lines
3.1 KiB
Python
Executable file
100 lines
3.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
"""
|
|
Creates a new task with corresponding description and tags.
|
|
|
|
Description and tags can be supplied via commandline through `-d` and `-t` options,
|
|
or interactively by using the options without supplying a string for them. E.g.:
|
|
|
|
`mutt2task` => task: Reply to <subject> from <sender>
|
|
`mutt2task -d "hello" -t one two` => task: hello +one +two
|
|
`mutt2task -d -t` => asks you interactively for description and tags
|
|
"""
|
|
|
|
import argparse
|
|
import email
|
|
import sys
|
|
import re
|
|
|
|
from tasklib import TaskWarrior, Task
|
|
|
|
|
|
def get_args():
|
|
parser = argparse.ArgumentParser(
|
|
description="Creates a task with given message and annotates the task with message id"
|
|
)
|
|
parser.add_argument(
|
|
"-d",
|
|
"--description",
|
|
nargs="?",
|
|
const=True,
|
|
default=None,
|
|
help="Supply a description for the task. Use the option as a flag to supply description interactively.",
|
|
)
|
|
parser.add_argument(
|
|
"-t",
|
|
"--tags",
|
|
nargs="*",
|
|
help="Supply any number of tags for the task. Use the option as a flag to supply tags interactively.",
|
|
)
|
|
parser.add_argument(
|
|
"-c",
|
|
"--clean",
|
|
action="store_true",
|
|
help="Remove subject annoyances like RE FWD on a best-effort basis.",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
args = get_args()
|
|
|
|
def clean_subject(subject):
|
|
to_remove = ["fwd", "re", "fw", "aw", "wg", "sv", "vs", "ref", "tr"]
|
|
for abbrev in to_remove:
|
|
patt = re.compile(r"^{}(?: |:)\s*".format(abbrev), re.IGNORECASE)
|
|
subject = patt.sub("", subject)
|
|
return subject
|
|
|
|
|
|
def get_task_description(message):
|
|
subject = clean_subject(message["subject"]) if args.clean else message["subject"]
|
|
description = 'Reply to "{}" from {}'.format(
|
|
subject, message["from"].split(" <")[0]
|
|
)
|
|
# automatically set description if one provided
|
|
if args.description and isinstance(args.description, str):
|
|
description = args.description
|
|
# otherwise let user enter one if option has been passed
|
|
elif args.description:
|
|
inp = input("Enter task description or press enter for default: ")
|
|
description = inp if inp else description
|
|
return description
|
|
|
|
|
|
def get_task_tags():
|
|
tags = ["mail"]
|
|
if args.tags and len(args.tags) > 0:
|
|
tags = sum([tag.split(" ") for tag in args.tags], [])
|
|
elif args.tags is not None and len(args.tags) == 0:
|
|
inp = input("Enter task tags or press enter for default: ")
|
|
tags = inp.split(" ") if inp else tags
|
|
return tags
|
|
|
|
|
|
def main():
|
|
try:
|
|
message = email.message_from_file(sys.stdin)
|
|
if not message:
|
|
print("Something went wrong, cannot parse mail.")
|
|
sys.exit(1)
|
|
tw = TaskWarrior("~/.local/share/task", create=False)
|
|
sys.stdin = open("/dev/tty") # make user able to add input again
|
|
task = Task(tw, description=get_task_description(message), tags=get_task_tags())
|
|
task.save()
|
|
task.add_annotation(message['message-id'])
|
|
except Exception as e:
|
|
print(e)
|
|
sys.exit(2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|