Add simple task clock management.

This commit is contained in:
Sergio Martínez Portela 2021-01-05 00:01:48 +01:00
parent c522afd290
commit e1f22d360c

View File

@ -4,6 +4,7 @@ import logging
import os import os
import re import re
import sys import sys
from datetime import datetime, timedelta
from enum import Enum from enum import Enum
from typing import List, Tuple, Union from typing import List, Tuple, Union
@ -53,7 +54,7 @@ NODE_PROPERTIES_RE = re.compile(
r"^(?P<indentation>\s*):(?P<key>[^+:]+)(?P<plus>\+)?:(?P<spacing>\s*)(?P<value>.+)$" r"^(?P<indentation>\s*):(?P<key>[^+:]+)(?P<plus>\+)?:(?P<spacing>\s*)(?P<value>.+)$"
) )
RAW_LINE_RE = re.compile(r"^\s*([^\s#:*]|$)") RAW_LINE_RE = re.compile(r"^\s*([^\s#:*]|$)")
BASE_TIME_STAMP_RE = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) (?P<dow>[^ ]+)( (?P<start_hour>\d{1,2}):(?P<start_minute>\d{1,2})(--(?P<end_hour>\d{1,2}):(?P<end_minute>\d{1,2}))?)?" BASE_TIME_STAMP_RE = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})( ?(?P<dow>[^ ]+))?( (?P<start_hour>\d{1,2}):(?P<start_minute>\d{1,2})(--(?P<end_hour>\d{1,2}):(?P<end_minute>\d{1,2}))?)?"
ACTIVE_TIME_STAMP_RE = re.compile(r"<{}>".format(BASE_TIME_STAMP_RE)) ACTIVE_TIME_STAMP_RE = re.compile(r"<{}>".format(BASE_TIME_STAMP_RE))
INACTIVE_TIME_STAMP_RE = re.compile(r"\[{}\]".format(BASE_TIME_STAMP_RE)) INACTIVE_TIME_STAMP_RE = re.compile(r"\[{}\]".format(BASE_TIME_STAMP_RE))
@ -180,6 +181,28 @@ class Headline:
self.is_todo = is_todo self.is_todo = is_todo
self.is_done = is_done self.is_done = is_done
@property
def clock(self):
times = []
for chunk in self.contents:
for line in chunk.get_raw().split("\n"):
content = line.strip()
if not content.startswith("CLOCK:"):
continue
time_seg = content[len("CLOCK:") :].strip()
if "--" in time_seg:
# TODO: Consider duration
start, end = time_seg.split("=")[0].split("--")
as_time_range = parse_org_time_range(start, end)
parsed = as_time_range
else:
parsed = parse_org_time(time_seg)
times.append(parsed)
return times
@property @property
def tags(self): def tags(self):
if isinstance(self.parent, OrgDoc): if isinstance(self.parent, OrgDoc):
@ -319,7 +342,6 @@ Property = collections.namedtuple(
# @TODO How are [YYYY-MM-DD HH:mm--HH:mm] and ([... HH:mm]--[... HH:mm]) differentiated ? # @TODO How are [YYYY-MM-DD HH:mm--HH:mm] and ([... HH:mm]--[... HH:mm]) differentiated ?
# @TODO Consider recurrence annotations # @TODO Consider recurrence annotations
TimeRange = collections.namedtuple("TimeRange", ("start_time", "end_time"))
Timestamp = collections.namedtuple( Timestamp = collections.namedtuple(
"Timestamp", ("active", "year", "month", "day", "dow", "hour", "minute") "Timestamp", ("active", "year", "month", "day", "dow", "hour", "minute")
) )
@ -377,6 +399,27 @@ def token_from_type(tok_type):
return ModeToMarker[tok_type] return ModeToMarker[tok_type]
class TimeRange:
def __init__(self, start_time, end_time):
self.start_time = start_time
self.end_time = end_time
@property
def duration(self) -> timedelta:
delta = self.end - self.start
return delta
@property
def start(self) -> datetime:
st = self.start_time
return datetime(st.year, st.month, st.day, st.hour or 0, st.minute or 0)
@property
def end(self) -> datetime:
et = self.end_time
return datetime(et.year, et.month, et.day, et.hour or 0, et.minute or 0)
def parse_org_time_range(start, end): def parse_org_time_range(start, end):
return TimeRange(parse_org_time(start), parse_org_time(end)) return TimeRange(parse_org_time(start), parse_org_time(end))
@ -425,7 +468,7 @@ def timerange_to_string(tr: TimeRange):
return timestamp_to_string(tr.start_time) + "--" + timestamp_to_string(tr.end_time) return timestamp_to_string(tr.start_time) + "--" + timestamp_to_string(tr.end_time)
def timestamp_to_string(ts): def timestamp_to_string(ts: Timestamp):
date = "{year}-{month:02d}-{day:02d}".format( date = "{year}-{month:02d}-{day:02d}".format(
year=ts.year, month=ts.month, day=ts.day year=ts.year, month=ts.month, day=ts.day
) )
@ -1163,8 +1206,12 @@ class OrgDocReader:
# @TODO properly consider "=> DURATION" section # @TODO properly consider "=> DURATION" section
start, end = value.split("=")[0].split("--") start, end = value.split("=")[0].split("--")
as_time_range = parse_org_time_range(start, end) as_time_range = parse_org_time_range(start, end)
if (as_time_range[0] is not None) and (as_time_range[1] is not None): if (as_time_range.start_time is not None) and (
value = TimeRange(as_time_range[0], as_time_range[1]) as_time_range.end_time is not None
):
value = as_time_range
else:
raise Exception("Unknown time range format: {}".format(value))
elif as_time := parse_org_time(value): elif as_time := parse_org_time(value):
value = as_time value = as_time