jrnlwarrior/jrnlwarrior.py

216 lines
5.5 KiB
Python
Raw Permalink Normal View History

2021-10-30 17:49:08 +00:00
#!/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
2021-11-01 09:28:55 +00:00
import subprocess
2021-10-31 16:06:28 +00:00
import options as opts
2021-10-31 17:40:30 +00:00
import json
from datetime import datetime
TODAY = datetime.today().strftime("%Y-%m-%d")
2021-10-31 10:40:36 +00:00
2021-10-30 17:49:08 +00:00
2021-10-31 15:20:41 +00:00
def get_todo_block_date(line, todo_block_title):
2021-10-31 11:05:20 +00:00
result = re.search(
2021-10-31 15:20:41 +00:00
rf"^\[(\d{{4}}-\d{{2}}-\d{{2}}).*\] ({re.escape(todo_block_title)}$)?",
2021-10-31 11:05:20 +00:00
line,
)
# we are entering todotxt data block
if result and result[2]:
return result[1]
2021-10-31 15:20:41 +00:00
# we enter block but not one for todotxt
2021-10-31 11:05:20 +00:00
elif result and not result[2]:
return False
# nothing changed, we didn't cross a date line
return "same"
2021-10-31 15:55:08 +00:00
def process_file(options):
2021-10-31 15:20:41 +00:00
fname = options.jrnl_fname
2021-10-30 17:49:08 +00:00
lines_to_delete = []
2021-10-31 17:40:30 +00:00
today_exists = False
curdate = ""
2021-10-30 17:49:08 +00:00
with open(fname) as file:
line_number = 0
for line in file:
line_number += 1
2021-11-01 09:30:07 +00:00
if handle_idea(line, options):
lines_to_delete.append(line_number)
2021-10-31 15:20:41 +00:00
todo_block = get_todo_block_date(line, options.todo_block_title)
2021-10-31 11:05:20 +00:00
if todo_block == False:
2021-10-31 15:34:51 +00:00
curdate = ""
2021-10-31 11:05:20 +00:00
continue
if todo_block != "same":
curdate = todo_block
2021-10-30 17:49:08 +00:00
continue
2021-10-31 15:34:51 +00:00
if not curdate:
continue
2021-10-30 17:49:08 +00:00
2021-10-31 15:55:08 +00:00
if handle_completed_tasks(line, curdate, options):
2021-10-30 17:49:08 +00:00
lines_to_delete.append(line_number)
if handle_open_tasks(line, curdate, options):
lines_to_delete.append(line_number)
2021-10-31 17:40:30 +00:00
if is_today(curdate):
today_exists = True
if lines_to_delete:
delete_lines_from_file(fname, lines_to_delete, options.dryrun)
2021-10-30 17:49:08 +00:00
if not today_exists and options.taskwarrior_fill_today:
add_today(fname, options)
2021-10-31 17:40:30 +00:00
2021-10-30 17:49:08 +00:00
2021-10-31 15:55:08 +00:00
def handle_completed_tasks(line, date, options):
completed_task = re.search(
rf"^{options.regex_task_completed} ((?:\([A-D]\))? ?.*)$",
line,
)
if completed_task and options.taskwarrior_log_completed:
2021-10-31 16:06:28 +00:00
log_completed_to_taskwarrior(completed_task[1], date, options)
2021-10-31 15:55:08 +00:00
return True
return False
2021-10-31 16:06:28 +00:00
def log_completed_to_taskwarrior(task_string, date, options):
overrides = options.taskwarrior_overrides
2021-10-30 17:49:08 +00:00
cmd = [
"task",
2021-10-31 14:44:41 +00:00
*overrides,
2021-10-30 17:49:08 +00:00
"log",
task_string,
2021-10-30 17:49:08 +00:00
f"entry:{date}",
f"end:{date}",
get_prio_string(task_string),
]
2021-10-31 16:06:28 +00:00
if options.dryrun:
2021-10-30 17:49:08 +00:00
print(cmd)
return
subprocess.run(cmd)
2021-10-30 17:49:08 +00:00
def handle_open_tasks(line, date, options):
completed_task = re.search(
rf"^{options.regex_task_incomplete} ((?:\([A-D]\))? ?.*)$",
line,
)
if completed_task and options.taskwarrior_add_incomplete:
add_incomplete_to_taskwarrior(completed_task[1], date, options)
return True
return False
def add_incomplete_to_taskwarrior(task_string, date, options):
overrides = options.taskwarrior_overrides
cmd = [
"task",
*overrides,
"add",
task_string,
f"entry:{date}",
f"scheduled:{date}",
get_prio_string(task_string),
]
if options.dryrun:
print(cmd)
return
subprocess.run(cmd)
2021-11-01 09:30:07 +00:00
def handle_idea(line, options):
completed_task = re.search(
rf"^{options.regex_task_idea} (.*)",
line,
)
if completed_task and options.taskwarrior_add_ideas:
add_idea_to_taskwarrior(completed_task[1], options)
return True
return False
def add_idea_to_taskwarrior(idea_string, options):
overrides = options.taskwarrior_overrides
cmd = [
"task",
*overrides,
"add",
"+idea",
"+maybe",
idea_string,
]
if options.dryrun:
print(cmd)
return
subprocess.run(cmd)
2021-11-01 09:30:07 +00:00
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 delete_lines_from_file(fname, lines, dryrun):
2021-10-31 15:20:41 +00:00
if dryrun:
2021-10-31 10:40:36 +00:00
print(f"deleting lines: {lines}")
2021-10-30 17:49:08 +00:00
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)
2021-10-31 17:40:30 +00:00
def is_today(cur_date):
if cur_date == TODAY:
return True
return False
def add_today(fname, options):
cmd = ["task", *options.taskwarrior_overrides, "+TODAY or +OVERDUE", "export"]
due_json = json.loads(subprocess.run(cmd, capture_output=True).stdout)
2021-10-31 18:14:26 +00:00
tasks = f"[{TODAY} 09:00] {options.todo_block_title}\n"
for task in due_json:
2021-10-31 17:40:30 +00:00
tasks += f"{task['description']}\n"
tasks += "\n"
2021-10-31 17:40:30 +00:00
if options.dryrun:
print(f"\nWRITING TODAY:\n{tasks}")
return
repl_fname = fname + ".bak"
with open(fname, "r") as read_file, open(repl_fname, "w") as write_file:
write_file.write(tasks)
write_file.write(read_file.read())
os.rename(repl_fname, fname)
2021-10-31 17:40:30 +00:00
2021-10-31 15:20:41 +00:00
if __name__ == "__main__":
2021-10-31 16:06:28 +00:00
process_file(opts.init())
2021-10-31 15:20:41 +00:00
sys.exit(0)