Compare commits
2 Commits
c522afd290
...
09f2aed8fe
Author | SHA1 | Date | |
---|---|---|---|
|
09f2aed8fe | ||
|
e1f22d360c |
@ -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
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ BASE_ENVIRONMENT = {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
HEADLINE_TAGS_RE = re.compile(r"((:[a-zA-Z0-9_@#%]+)+:)")
|
HEADLINE_TAGS_RE = re.compile(r"((:[a-zA-Z0-9_@#%]+)+:)\s*$")
|
||||||
HEADLINE_RE = re.compile(r"^(?P<stars>\*+) (?P<spacing>\s*)(?P<line>.*?)$")
|
HEADLINE_RE = re.compile(r"^(?P<stars>\*+) (?P<spacing>\s*)(?P<line>.*?)$")
|
||||||
KEYWORDS_RE = re.compile(
|
KEYWORDS_RE = re.compile(
|
||||||
r"^(?P<indentation>\s*)#\+(?P<key>[^:\[]+)(\[(?P<options>[^\]]*)\])?:(?P<spacing>\s*)(?P<value>.*)$"
|
r"^(?P<indentation>\s*)#\+(?P<key>[^:\[]+)(\[(?P<options>[^\]]*)\])?:(?P<spacing>\s*)(?P<value>.*)$"
|
||||||
@ -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
|
||||||
)
|
)
|
||||||
@ -847,14 +890,14 @@ def parse_headline(hl, doc, parent) -> Headline:
|
|||||||
hl_state = None
|
hl_state = None
|
||||||
title = line
|
title = line
|
||||||
is_done = is_todo = False
|
is_done = is_todo = False
|
||||||
for state in doc.todo_keywords:
|
for state in doc.todo_keywords or []:
|
||||||
if title.startswith(state + " "):
|
if title.startswith(state + " "):
|
||||||
hl_state = state
|
hl_state = state
|
||||||
title = title[len(state + " ") :]
|
title = title[len(state + " ") :]
|
||||||
is_todo = True
|
is_todo = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
for state in doc.done_keywords:
|
for state in doc.done_keywords or []:
|
||||||
if title.startswith(state + " "):
|
if title.startswith(state + " "):
|
||||||
hl_state = state
|
hl_state = state
|
||||||
title = title[len(state + " ") :]
|
title = title[len(state + " ") :]
|
||||||
@ -979,9 +1022,18 @@ class OrgDoc:
|
|||||||
return (line.linenum, line.line)
|
return (line.linenum, line.line)
|
||||||
|
|
||||||
def dump_headline(self, headline):
|
def dump_headline(self, headline):
|
||||||
yield "*" * headline.depth + " " + headline.orig.group(
|
|
||||||
|
tags = ""
|
||||||
|
if len(headline.shallow_tags) > 0:
|
||||||
|
tags = ":" + ":".join(headline.shallow_tags) + ":"
|
||||||
|
|
||||||
|
state = ""
|
||||||
|
if headline.state:
|
||||||
|
state = headline.state + " "
|
||||||
|
|
||||||
|
yield "*" * headline.depth + " " + state + headline.orig.group(
|
||||||
"spacing"
|
"spacing"
|
||||||
) + headline.title
|
) + headline.title + tags
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
KW_T = 0
|
KW_T = 0
|
||||||
@ -1163,8 +1215,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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user