jrnlwarrior/open-todo-txt.py

108 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
# From: https://gist.github.com/varunagrawal/2b93c5dc721520ff6876e940c420ab05
# This hooks script logs any finished tasks currently in the todo.txt file
# pointed to by its settings.
# The on-exit event is triggered once, after all processing is complete.
import re
import os
import sys
import subprocess
import options
def get_todo_block_date(line, todo_block_title):
result = re.search(
rf"^\[(\d{{4}}-\d{{2}}-\d{{2}}).*\] ({re.escape(todo_block_title)}$)?",
line,
)
# we are entering todotxt data block
if result and result[2]:
return result[1]
# we enter block but not one for todotxt
elif result and not result[2]:
return False
# nothing changed, we didn't cross a date line
return "same"
def parse_file(options):
fname = options.jrnl_fname
lines_to_delete = []
with open(fname) as file:
line_number = 0
for line in file:
line_number += 1
todo_block = get_todo_block_date(line, options.todo_block_title)
if todo_block == False:
continue
if todo_block != "same":
curdate = todo_block
continue
completed_task = re.search(r"^x ((?:\([A-D]\))? ?.*)$", line)
if completed_task and options.taskwarrior_log_done:
log_done_to_taskwarrior(completed_task[1], curdate, options.dryrun)
lines_to_delete.append(line_number)
if lines_to_delete:
delete_logged_tasks_from_file(fname, lines_to_delete, options.dryrun)
def get_prio_string(task_string):
prio = re.search(r"^\(([ABC])\) (.*)$", task_string)
prio_string = ""
if prio:
task_string = prio[2]
if prio[1] == "A":
prio_string = "prio:H"
elif prio[1] == "B":
prio_string = "prio:M"
elif prio[1] == "C":
prio_string = "prio:L"
return prio_string
def log_done_to_taskwarrior(task_string, date, dryrun):
overrides = ["rc.context=none", "rc.verbose=nothing", "rc.hooks=0"]
cmd = [
"task",
*overrides,
"log",
f'"{task_string}"',
f"entry:{date}",
f"end:{date}",
get_prio_string(task_string),
]
if dryrun:
print(cmd)
return
subprocess.Popen(cmd)
def delete_logged_tasks_from_file(fname, lines, dryrun):
if dryrun:
print(f"deleting lines: {lines}")
return
cur_line = 0
repl_file = fname + ".bak"
with open(fname) as read_file, open(repl_file, "w") as write_file:
for line in read_file:
cur_line += 1
if lines and cur_line == lines[0]:
lines.pop(0)
continue
write_file.write(line)
os.rename(repl_file, fname)
if __name__ == "__main__":
parse_file(options.init())
sys.exit(0)