Fix Headline spacing, add default TODO/DONE keywords.

Additionally, add util function to iterate over all headlines, and fix
Timestamp.to_datetime() to work even when no time was given.
This commit is contained in:
Sergio Martínez Portela 2021-01-17 13:30:38 +01:00
parent cde3481958
commit 1412a2bde1

View File

@ -8,7 +8,7 @@ import re
import sys import sys
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from enum import Enum from enum import Enum
from typing import List, Tuple, Union from typing import Generator, List, Tuple, Union
BASE_ENVIRONMENT = { BASE_ENVIRONMENT = {
"org-footnote-section": "Footnotes", "org-footnote-section": "Footnotes",
@ -45,8 +45,11 @@ BASE_ENVIRONMENT = {
), ),
} }
DEFAULT_TODO_KEYWORDS = ["TODO"]
DEFAULT_DONE_KEYWORDS = ["DONE"]
HEADLINE_TAGS_RE = re.compile(r"((:[a-zA-Z0-9_@#%]+)+:)\s*$") 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>.*)$"
) )
@ -182,6 +185,7 @@ class Headline:
parent, parent,
is_todo, is_todo,
is_done, is_done,
spacing,
): ):
self.start_line = start_line self.start_line = start_line
self.depth = depth self.depth = depth
@ -205,6 +209,7 @@ class Headline:
self.scheduled = None self.scheduled = None
self.deadline = None self.deadline = None
self.closed = None self.closed = None
self.spacing = spacing
# Read planning line # Read planning line
planning_line = self.get_element_in_line(start_line + 1) planning_line = self.get_element_in_line(start_line + 1)
@ -459,8 +464,11 @@ class Timestamp:
self.minute = minute self.minute = minute
self.repetition = repetition self.repetition = repetition
def to_datetime(self) -> datetime: def to_datetime(self) -> Union[datetime, date]:
return datetime(self.year, self.month, self.day, self.hour, self.minute) if self.hour is not None:
return datetime(self.year, self.month, self.day, self.hour, self.minute)
else:
return datetime(self.year, self.month, self.day, 0, 0)
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, Timestamp): if not isinstance(other, Timestamp):
@ -1089,6 +1097,7 @@ def dump_contents(raw):
def parse_headline(hl, doc, parent) -> Headline: def parse_headline(hl, doc, parent) -> Headline:
stars = hl["orig"].group("stars") stars = hl["orig"].group("stars")
depth = len(stars) depth = len(stars)
spacing = hl["orig"].group("spacing")
# TODO: Parse line for priority, cookies and tags # TODO: Parse line for priority, cookies and tags
line = hl["orig"].group("line") line = hl["orig"].group("line")
@ -1139,6 +1148,7 @@ def parse_headline(hl, doc, parent) -> Headline:
parent=parent, parent=parent,
is_todo=is_todo, is_todo=is_todo,
is_done=is_done, is_done=is_done,
spacing=spacing,
) )
headline.children = [ headline.children = [
@ -1149,8 +1159,8 @@ def parse_headline(hl, doc, parent) -> Headline:
class OrgDoc: class OrgDoc:
def __init__(self, headlines, keywords, contents): def __init__(self, headlines, keywords, contents):
self.todo_keywords = None self.todo_keywords = DEFAULT_TODO_KEYWORDS
self.done_keywords = None self.done_keywords = DEFAULT_DONE_KEYWORDS
for keyword in keywords: for keyword in keywords:
if keyword.key == "TODO": if keyword.key == "TODO":
@ -1184,6 +1194,14 @@ class OrgDoc:
def getTopHeadlines(self): def getTopHeadlines(self):
return self.headlines return self.headlines
def getAllHeadlines(self) -> Generator[Headline]:
todo = self.headlines[::-1] # We go backwards, to pop/append and go depth-first
while len(todo) != 0:
hl = todo.pop()
todo.extend(hl.children[::-1])
yield hl
def get_code_snippets(self): def get_code_snippets(self):
for headline in self.headlines: for headline in self.headlines:
yield from headline.get_code_snippets() yield from headline.get_code_snippets()
@ -1244,9 +1262,7 @@ class OrgDoc:
if headline.state: if headline.state:
state = headline.state + " " state = headline.state + " "
yield "*" * headline.depth + " " + state + headline.orig.group( yield "*" * headline.depth + headline.spacing + state + headline.title + tags
"spacing"
) + headline.title + tags
planning = headline.get_planning_line() planning = headline.get_planning_line()
if planning is not None: if planning is not None: