Compare commits

..

No commits in common. "99e44fd8b29aa68ca5a6357b8d51f50ca0e03427" and "28ddd3e44f80ae82f8e7ccde48d94cf96b18c366" have entirely different histories.

7 changed files with 92 additions and 433 deletions

View File

@ -27,7 +27,7 @@ class PropertyNode:
self.value = value self.value = value
def __repr__(self): def __repr__(self):
return "{{{}: {}}}".format(self.key, self.value) return "{{{}: {}}".format(self.key, self.value)
class ListGroupNode: class ListGroupNode:
@ -89,12 +89,11 @@ class BlockNode:
class CodeBlock(BlockNode): class CodeBlock(BlockNode):
def __init__(self, header, subtype, arguments): def __init__(self, header, subtype):
super().__init__() super().__init__()
self.header = header self.header = header
self.lines = None self.lines = None
self.subtype = subtype self.subtype = subtype
self.arguments = arguments
def set_lines(self, lines): def set_lines(self, lines):
self.lines = lines self.lines = lines

View File

@ -92,10 +92,10 @@ LIST_ITEM_RE = re.compile(
) )
# Org-Babel # Org-Babel
BEGIN_BLOCK_RE = re.compile(r"^\s*#\+BEGIN_(?P<subtype>[^ ]+)(?P<arguments>.*)$", re.I) BEGIN_BLOCK_RE = re.compile(r"^\s*#\+BEGIN_(?P<subtype>[^ ]+)(?P<content>.*)$", re.I)
END_BLOCK_RE = re.compile(r"^\s*#\+END_(?P<subtype>[^ ]+)\s*$", re.I) END_BLOCK_RE = re.compile(r"^\s*#\+END_(?P<subtype>[^ ]+)\s*$", re.I)
RESULTS_DRAWER_RE = re.compile(r"^\s*:results:\s*$", re.I) RESULTS_DRAWER_RE = re.compile(r"^\s*:results:\s*$", re.I)
CodeSnippet = collections.namedtuple("CodeSnippet", ("name", "content", "result", "arguments")) CodeSnippet = collections.namedtuple("CodeSnippet", ("name", "content", "result"))
# Groupings # Groupings
NON_FINISHED_GROUPS = (type(None), dom.ListGroupNode, dom.ResultsDrawerNode, dom.PropertyDrawerNode) NON_FINISHED_GROUPS = (type(None), dom.ListGroupNode, dom.ResultsDrawerNode, dom.PropertyDrawerNode)
@ -154,26 +154,6 @@ class RangeInRaw:
contents.insert(start_idx + i + 1, element) contents.insert(start_idx + i + 1, element)
def unescape_block_lines(lines: str) -> str:
"""
Remove leading ',' from block_lines if they escape `*` characters.
"""
i = 0
lines = lines.split('\n')
while i < len(lines):
line = lines[i]
if (line.lstrip(' ').startswith(',')
and line.lstrip(' ,').startswith('*')
):
# Remove leading ','
lead_pos = line.index(',')
line = line[:lead_pos] + line[lead_pos + 1:]
lines[i] = line
i += 1
return '\n'.join(lines)
def get_links_from_content(content): def get_links_from_content(content):
in_link = False in_link = False
in_description = False in_description = False
@ -376,7 +356,7 @@ class Headline:
end = line.linenum end = line.linenum
lines = self.get_lines_between(start + 1, end) lines = self.get_lines_between(start + 1, end)
contents = unescape_block_lines("\n".join(lines)) contents = "\n".join(lines)
if contents.endswith("\n"): if contents.endswith("\n"):
# This is not ideal, but to avoid having to do this maybe # This is not ideal, but to avoid having to do this maybe
# the content parsing must be re-thinked # the content parsing must be re-thinked
@ -396,32 +376,18 @@ class Headline:
current_node.append(dom.PropertyNode(line.key, line.value)) current_node.append(dom.PropertyNode(line.key, line.value))
elif isinstance(line, Text): elif isinstance(line, Text):
tree_up = list(indentation_tree) if isinstance(current_node, dom.BlockNode):
while len(tree_up) > 0: current_node.append(dom.Text(line))
node = tree_up[-1] elif isinstance(current_node, dom.DrawerNode):
if (isinstance(node, dom.BlockNode) current_node.append(dom.Text(line))
or isinstance(node, dom.DrawerNode)
):
node.append(dom.Text(line))
current_node = node
contents = []
break
elif ((not isinstance(node, dom.TableNode)) and
(type(node) not in NON_FINISHED_GROUPS)
):
raise NotImplementedError('Not implemented node type: {} (headline_id={}, line={}, doc={})'.format(
node,
self.id,
line.linenum,
self.doc.path,
))
else:
tree_up.pop(-1)
else: else:
if isinstance(current_node, dom.TableNode):
pass # No problem here
elif type(current_node) not in NON_FINISHED_GROUPS:
raise NotImplementedError('Not implemented node type: {}'.format(current_node))
current_node = None current_node = None
contents = [] contents = []
tree.append(dom.Text(text_to_dom(line.contents, line))) tree.append(dom.Text(text_to_dom(line.contents, line)))
indentation_tree = tree_up
elif isinstance(line, ListItem): elif isinstance(line, ListItem):
if (current_node is None if (current_node is None
@ -429,12 +395,9 @@ class Headline:
or isinstance(current_node, dom.BlockNode) or isinstance(current_node, dom.BlockNode)
or isinstance(current_node, dom.DrawerNode) or isinstance(current_node, dom.DrawerNode)
): ):
was_node = current_node
current_node = dom.ListGroupNode() current_node = dom.ListGroupNode()
if was_node is None: if current_node is None:
tree.append(current_node) tree.append(current_node)
else:
was_node.append(current_node)
indentation_tree.append(current_node) indentation_tree.append(current_node)
if not isinstance(current_node, dom.ListGroupNode): if not isinstance(current_node, dom.ListGroupNode):
if not isinstance(current_node, dom.ListGroupNode): if not isinstance(current_node, dom.ListGroupNode):
@ -457,22 +420,18 @@ class Headline:
current_node = sublist current_node = sublist
indentation_tree.append(current_node) indentation_tree.append(current_node)
while len(indentation_tree) > 0: while len(indentation_tree) > 0 and (
list_children = [ (len(indentation_tree[-1].children) > 0)
and len(
[
c c
for c in indentation_tree[-1].children for c in indentation_tree[-1].children
if isinstance(c, dom.ListItem) if isinstance(c, dom.ListItem)
] ][-1].orig.indentation
)
if (len(list_children) == 0): > len(line.indentation)
break ):
if ((len(list_children[-1].orig.indentation) rem = indentation_tree.pop()
<= len(line.indentation))):
# No more breaking out of lists, it's indentation
# is less than ours
break
rem = indentation_tree.pop(-1)
if len(indentation_tree) == 0: if len(indentation_tree) == 0:
indentation_tree.append(rem) indentation_tree.append(rem)
current_node = rem current_node = rem
@ -489,15 +448,9 @@ class Headline:
tree.append(current_node) tree.append(current_node)
# TODO: Allow indentation of this element inside others # TODO: Allow indentation of this element inside others
indentation_tree = [current_node] indentation_tree = [current_node]
elif not isinstance(current_node, dom.TableNode): if not isinstance(current_node, dom.TableNode):
if isinstance(current_node, dom.ListGroupNode): if not isinstance(current_node, dom.TableNode):
# As an item inside a list logging.warning("Expected a {}, found: {} on line {}".format(dom.TableNode, current_node, line.linenum))
list_node = current_node
current_node = dom.TableNode()
list_node.append(current_node)
indentation_tree.append(current_node)
else:
logging.debug("Expected a {}, found: {} on line {}".format(dom.TableNode, current_node, line.linenum))
# This can happen. Frequently inside a LogDrawer # This can happen. Frequently inside a LogDrawer
if len(line.cells) > 0 and len(line.cells[0]) > 0 and line.cells[0][0] == '-': if len(line.cells) > 0 and len(line.cells[0]) > 0 and line.cells[0][0] == '-':
@ -511,7 +464,7 @@ class Headline:
and line.delimiter_type == DelimiterLineType.BEGIN_BLOCK and line.delimiter_type == DelimiterLineType.BEGIN_BLOCK
): ):
assert type(current_node) in NON_FINISHED_GROUPS assert type(current_node) in NON_FINISHED_GROUPS
current_node = dom.CodeBlock(line, line.type_data.subtype, line.arguments) current_node = dom.CodeBlock(line, line.type_data.subtype)
elif isinstance(line, Keyword): elif isinstance(line, Keyword):
logging.warning("Keywords not implemented on `as_dom()`") logging.warning("Keywords not implemented on `as_dom()`")
@ -559,6 +512,8 @@ class Headline:
tree_up.pop(-1) tree_up.pop(-1)
else: else:
raise Exception('Unexpected node ({}) on headline (id={}), line {}'.format(current_node, self.id, linenum)) raise Exception('Unexpected node ({}) on headline (id={}), line {}'.format(current_node, self.id, linenum))
if self.id == 'd07fcf27-d6fc-41e3-a9d0-b2e2902aec23':
print("Found node:", current_node)
current_node = None current_node = None
elif content.strip().upper() == ":RESULTS:": elif content.strip().upper() == ":RESULTS:":
assert current_node is None assert current_node is None
@ -579,26 +534,14 @@ class Headline:
last_line = None last_line = None
for li in self.list_items: for li in self.list_items:
if last_line is None: if last_line == li.linenum - 1:
lists.append([li])
else:
num_lines = li.linenum - (last_line + 1)
lines_between = ''.join(['\n' + l
for l in self.get_lines_between(last_line + 1, li.linenum)]
)
# Only empty lines
if ((num_lines == lines_between.count('\n'))
and (len(lines_between.strip()) == 0)
):
lists[-1].append(li) lists[-1].append(li)
else: else:
lists.append([li]) lists.append([li])
last_line = li.linenum + sum(c.count('\n') for c in li.content) last_line = li.linenum
return lists return lists
# @DEPRECATED: use `get_lists`
def getLists(self): def getLists(self):
return self.get_lists() return self.get_lists()
@ -680,9 +623,6 @@ class Headline:
else: else:
return list(self.shallow_tags) + self.parent.tags return list(self.shallow_tags) + self.parent.tags
def add_tag(self, tag: str):
self.shallow_tags.append(tag)
def get_property(self, name: str, default=None): def get_property(self, name: str, default=None):
for prop in self.properties: for prop in self.properties:
if prop.key == name: if prop.key == name:
@ -736,14 +676,18 @@ class Headline:
for lst in self.get_lists(): for lst in self.get_lists():
for item in lst: for item in lst:
if item.tag:
yield from get_links_from_content(item.tag)
yield from get_links_from_content(item.content) yield from get_links_from_content(item.content)
def get_lines_between(self, start, end): def get_lines_between(self, start, end):
for line in self.contents: for line in self.contents:
if start <= line.linenum < end: if start <= line.linenum < end:
yield "".join(line.get_raw()) text = []
for item in line.contents:
if isinstance(item, str):
text.append(item)
elif isinstance(item, MarkerType):
text.append(ModeToMarker[item])
yield "".join(text)
def get_contents(self, format): def get_contents(self, format):
if format == "raw": if format == "raw":
@ -793,19 +737,17 @@ class Headline:
inside_code = False inside_code = False
sections = [] sections = []
arguments = None
for delimiter in self.delimiters: for delimiter in self.delimiters:
if delimiter.delimiter_type == DelimiterLineType.BEGIN_BLOCK and delimiter.type_data.subtype.lower() == "src": if delimiter.delimiter_type == DelimiterLineType.BEGIN_BLOCK and delimiter.type_data.subtype.lower() == "src":
line_start = delimiter.linenum line_start = delimiter.linenum
inside_code = True inside_code = True
arguments = delimiter.arguments
elif delimiter.delimiter_type == DelimiterLineType.END_BLOCK and delimiter.type_data.subtype.lower() == "src": elif delimiter.delimiter_type == DelimiterLineType.END_BLOCK and delimiter.type_data.subtype.lower() == "src":
inside_code = False inside_code = False
start, end = line_start, delimiter.linenum start, end = line_start, delimiter.linenum
lines = self.get_lines_between(start + 1, end) lines = self.get_lines_between(start + 1, end)
contents = unescape_block_lines("\n".join(lines)) contents = "\n".join(lines)
if contents.endswith("\n"): if contents.endswith("\n"):
# This is not ideal, but to avoid having to do this maybe # This is not ideal, but to avoid having to do this maybe
# the content parsing must be re-thinked # the content parsing must be re-thinked
@ -816,10 +758,8 @@ class Headline:
"line_first": start + 1, "line_first": start + 1,
"line_last": end - 1, "line_last": end - 1,
"content": contents, "content": contents,
"arguments": arguments,
} }
) )
arguments = None
line_start = None line_start = None
for kword in self.keywords: for kword in self.keywords:
@ -870,40 +810,10 @@ class Headline:
name = None name = None
content = section["content"] content = section["content"]
code_result = section.get("result", None) code_result = section.get("result", None)
arguments = section.get("arguments", None) results.append(CodeSnippet(name=name, content=content, result=code_result))
results.append(CodeSnippet(name=name, content=content, result=code_result, arguments=arguments))
return results return results
def create_headline_at_end(self) -> Headline:
headline = Headline(
start_line=1,
depth=self.depth + 1,
orig=None,
properties=[],
keywords=[],
priority_start=None,
priority=None,
title_start=None,
title="",
state="",
tags_start=None,
tags=[],
contents=[],
children=[],
structural=[],
delimiters=[],
list_items=[],
table_rows=[],
parent=self,
is_todo=False,
is_done=False,
spacing=" ",
)
self.children.append(headline)
return headline
RawLine = collections.namedtuple("RawLine", ("linenum", "line")) RawLine = collections.namedtuple("RawLine", ("linenum", "line"))
Keyword = collections.namedtuple( Keyword = collections.namedtuple(
@ -913,34 +823,22 @@ Property = collections.namedtuple(
"Property", ("linenum", "match", "key", "value", "options") "Property", ("linenum", "match", "key", "value", "options")
) )
class ListItem: ListItem = collections.namedtuple(
def __init__(self, "ListItem",
linenum, match, (
indentation, "linenum",
bullet, counter, counter_sep, "match",
checkbox_indentation, checkbox_value, "indentation",
tag_indentation, tag, "bullet",
content, "counter",
): "counter_sep",
self.linenum = linenum "checkbox_indentation",
self.match = match "checkbox_value",
self.indentation = indentation "tag_indentation",
self.bullet = bullet "tag",
self.counter = counter "content",
self.counter_sep = counter_sep ),
self.checkbox_indentation = checkbox_indentation )
self.checkbox_value = checkbox_value
self.tag_indentation = tag_indentation
self.tag = tag
self.content = content
@property
def text_start_pos(self):
return len(self.indentation) + 1 # Indentation + bullet
def append_line(self, line):
self.content += parse_content_block('\n' + line).contents
TableRow = collections.namedtuple( TableRow = collections.namedtuple(
"TableRow", "TableRow",
( (
@ -1054,7 +952,7 @@ BlockDelimiterTypeData = collections.namedtuple(
) )
DelimiterLine = collections.namedtuple( DelimiterLine = collections.namedtuple(
"DelimiterLine", ("linenum", "line", "delimiter_type", "type_data", "arguments") "DelimiterLine", ("linenum", "line", "delimiter_type", "type_data")
) )
@ -1102,8 +1000,6 @@ def token_from_type(tok_type):
class TimeRange: class TimeRange:
def __init__(self, start_time: OrgTime, end_time: OrgTime): def __init__(self, start_time: OrgTime, end_time: OrgTime):
assert start_time is not None
assert end_time is not None
self.start_time = start_time self.start_time = start_time
self.end_time = end_time self.end_time = end_time
@ -1644,19 +1540,13 @@ def parse_contents(raw_contents: List[RawLine]):
return [parse_content_block(block) for block in blocks] return [parse_content_block(block) for block in blocks]
def parse_content_block(raw_contents: Union[List[RawLine],str]): def parse_content_block(raw_contents: List[RawLine]):
contents_buff = [] contents_buff = []
if isinstance(raw_contents, str):
contents_buff.append(raw_contents)
else:
for line in raw_contents: for line in raw_contents:
contents_buff.append(line.line) contents_buff.append(line.line)
contents = "\n".join(contents_buff) contents = "\n".join(contents_buff)
tokens = tokenize_contents(contents) tokens = tokenize_contents(contents)
if isinstance(raw_contents, str):
current_line = None
else:
current_line = raw_contents[0].linenum current_line = raw_contents[0].linenum
contents = [] contents = []
@ -1684,9 +1574,7 @@ def dump_contents(raw):
elif isinstance(raw, ListItem): elif isinstance(raw, ListItem):
bullet = raw.bullet if raw.bullet else raw.counter + raw.counter_sep bullet = raw.bullet if raw.bullet else raw.counter + raw.counter_sep
content_full = token_list_to_raw(raw.content) content = token_list_to_raw(raw.content)
content_lines = content_full.split('\n')
content = '\n'.join(content_lines)
checkbox = f"[{raw.checkbox_value}]" if raw.checkbox_value else "" checkbox = f"[{raw.checkbox_value}]" if raw.checkbox_value else ""
tag = f"{raw.tag_indentation}{token_list_to_raw(raw.tag or '')}::" if raw.tag or raw.tag_indentation else "" tag = f"{raw.tag_indentation}{token_list_to_raw(raw.tag or '')}::" if raw.tag or raw.tag_indentation else ""
return ( return (
@ -1916,12 +1804,7 @@ class OrgDoc:
if headline.state: if headline.state:
state = headline.state + " " state = headline.state + " "
raw_title = token_list_to_raw(headline.title.contents) yield "*" * headline.depth + headline.spacing + state + token_list_to_raw(headline.title.contents) + tags
tags_padding = ""
if not raw_title.endswith(" ") and tags:
tags_padding = " "
yield "*" * headline.depth + headline.spacing + state + raw_title + tags_padding + tags
planning = headline.get_planning_line() planning = headline.get_planning_line()
if planning is not None: if planning is not None:
@ -2080,19 +1963,19 @@ class OrgDocReader:
def add_list_item_line(self, linenum: int, match: re.Match) -> int: def add_list_item_line(self, linenum: int, match: re.Match) -> int:
li = ListItem( li = ListItem(
linenum=linenum, linenum,
match=match, match,
indentation=match.group("indentation"), match.group("indentation"),
bullet=match.group("bullet"), match.group("bullet"),
counter=match.group("counter"), match.group("counter"),
counter_sep=match.group("counter_sep"), match.group("counter_sep"),
checkbox_indentation=match.group("checkbox_indentation"), match.group("checkbox_indentation"),
checkbox_value=match.group("checkbox_value"), match.group("checkbox_value"),
tag_indentation=match.group("tag_indentation"), match.group("tag_indentation"),
tag=parse_content_block( parse_content_block(
[RawLine(linenum=linenum, line=match.group("tag"))] [RawLine(linenum=linenum, line=match.group("tag"))]
).contents if match.group("tag") else None, ).contents if match.group("tag") else None,
content=parse_content_block( parse_content_block(
[RawLine(linenum=linenum, line=match.group("content"))] [RawLine(linenum=linenum, line=match.group("content"))]
).contents, ).contents,
) )
@ -2101,7 +1984,6 @@ class OrgDocReader:
self.list_items.append(li) self.list_items.append(li)
else: else:
self.headline_hierarchy[-1]["list_items"].append(li) self.headline_hierarchy[-1]["list_items"].append(li)
return li
def add_table_line(self, linenum: int, line: str) -> int: def add_table_line(self, linenum: int, line: str) -> int:
chunks = line.split('|') chunks = line.split('|')
@ -2151,7 +2033,7 @@ class OrgDocReader:
def add_begin_block_line(self, linenum: int, match: re.Match): def add_begin_block_line(self, linenum: int, match: re.Match):
line = DelimiterLine(linenum, match.group(0), DelimiterLineType.BEGIN_BLOCK, line = DelimiterLine(linenum, match.group(0), DelimiterLineType.BEGIN_BLOCK,
BlockDelimiterTypeData(match.group("subtype")), match.group('arguments')) BlockDelimiterTypeData(match.group("subtype")))
if len(self.headline_hierarchy) == 0: if len(self.headline_hierarchy) == 0:
self.delimiters.append(line) self.delimiters.append(line)
else: else:
@ -2159,7 +2041,7 @@ class OrgDocReader:
def add_end_block_line(self, linenum: int, match: re.Match): def add_end_block_line(self, linenum: int, match: re.Match):
line = DelimiterLine(linenum, match.group(0), DelimiterLineType.END_BLOCK, line = DelimiterLine(linenum, match.group(0), DelimiterLineType.END_BLOCK,
BlockDelimiterTypeData(match.group("subtype")), None) BlockDelimiterTypeData(match.group("subtype")))
if len(self.headline_hierarchy) == 0: if len(self.headline_hierarchy) == 0:
self.delimiters.append(line) self.delimiters.append(line)
else: else:
@ -2211,25 +2093,6 @@ class OrgDocReader:
reader = enumerate(lines) reader = enumerate(lines)
in_drawer = False in_drawer = False
in_block = False in_block = False
list_item_indentation = None
list_item = None
def add_raw_line_with_possible_indentation(linenum, line):
added = False
nonlocal list_item
nonlocal list_item_indentation
if list_item:
if ((line[:list_item.text_start_pos].strip() == '')
or (len(line.strip()) == 0)
):
list_item.append_line(line)
added = True
else:
list_item = None
list_item_indentation = None
if not added:
self.add_raw_line(linenum, line)
for lnum, line in reader: for lnum, line in reader:
linenum = lnum + 1 linenum = lnum + 1
@ -2238,58 +2101,41 @@ class OrgDocReader:
if m := END_BLOCK_RE.match(line): if m := END_BLOCK_RE.match(line):
self.add_end_block_line(linenum, m) self.add_end_block_line(linenum, m)
in_block = False in_block = False
list_item_indentation = None
list_item = None
else: else:
add_raw_line_with_possible_indentation(linenum, line) self.add_raw_line(linenum, line)
elif m := HEADLINE_RE.match(line): elif m := HEADLINE_RE.match(line):
list_item_indentation = None
list_item = None
self.add_headline(linenum, m) self.add_headline(linenum, m)
elif m := LIST_ITEM_RE.match(line): elif m := LIST_ITEM_RE.match(line):
list_item = self.add_list_item_line(linenum, m) self.add_list_item_line(linenum, m)
list_item_indentation = m.group("indentation")
elif m := RAW_LINE_RE.match(line): elif m := RAW_LINE_RE.match(line):
add_raw_line_with_possible_indentation(linenum, line) self.add_raw_line(linenum, line)
# Org-babel # Org-babel
elif m := BEGIN_BLOCK_RE.match(line): elif m := BEGIN_BLOCK_RE.match(line):
self.add_begin_block_line(linenum, m) self.add_begin_block_line(linenum, m)
in_block = True in_block = True
list_item_indentation = None
list_item = None
elif m := END_BLOCK_RE.match(line): elif m := END_BLOCK_RE.match(line):
self.add_end_block_line(linenum, m) self.add_end_block_line(linenum, m)
in_block = False in_block = False
list_item_indentation = None
list_item = None
# Generic properties # Generic properties
elif m := KEYWORDS_RE.match(line): elif m := KEYWORDS_RE.match(line):
self.add_keyword_line(linenum, m) self.add_keyword_line(linenum, m)
elif m := DRAWER_END_RE.match(line): elif m := DRAWER_END_RE.match(line):
self.add_drawer_end_line(linenum, line, m) self.add_drawer_end_line(linenum, line, m)
in_drawer = False in_drawer = False
list_item_indentation = None
list_item = None
elif (not in_drawer) and (m := DRAWER_START_RE.match(line)): elif (not in_drawer) and (m := DRAWER_START_RE.match(line)):
self.add_property_drawer_line(linenum, line, m) self.add_property_drawer_line(linenum, line, m)
in_drawer = True in_drawer = True
list_item_indentation = None
list_item = None
elif (not in_drawer) and (m := RESULTS_DRAWER_RE.match(line)): elif (not in_drawer) and (m := RESULTS_DRAWER_RE.match(line)):
self.add_results_drawer_line(linenum, line, m) self.add_results_drawer_line(linenum, line, m)
in_drawer = True in_drawer = True
list_item_indentation = None
list_item = None
elif m := NODE_PROPERTIES_RE.match(line): elif m := NODE_PROPERTIES_RE.match(line):
self.add_node_properties_line(linenum, m) self.add_node_properties_line(linenum, m)
elif line.strip().startswith('|'): elif line.strip().startswith('|'):
self.add_table_line(linenum, line) self.add_table_line(linenum, line)
list_item_indentation = None
list_item = None
# Not captured # Not captured
else: else:
add_raw_line_with_possible_indentation(linenum, line) self.add_raw_line(linenum, line)
except: except:
logging.error("Error line {}: {}".format(linenum + 1, line)) logging.error("Error line {}: {}".format(linenum + 1, line))
raise raise

View File

@ -36,16 +36,3 @@ exit 0 # Comment
This is another test This is another test
with two lines too with two lines too
:end: :end:
* Escaped code
:PROPERTIES:
:ID: 04-code-escaped-code-id
:CREATED: [2020-01-01 Wed 01:01]
:END:
#+BEGIN_SRC c :results drawer
/* This code has to be escaped to
,* avoid confusion with new headlines.
,*/
main(){}
#+END_SRC

View File

@ -1,5 +1,5 @@
#+TITLE: 06-Lists #+TITLE: 06-Links
#+DESCRIPTION: Simple org file to test lists #+DESCRIPTION: Simple org file to test links
#+TODO: TODO(t) PAUSED(p) | DONE(d) #+TODO: TODO(t) PAUSED(p) | DONE(d)
@ -51,25 +51,3 @@ Also with markup
- _Key_ :: _Value_ - _Key_ :: _Value_
- /Key/ 2 :: /Value/ 2 - /Key/ 2 :: /Value/ 2
* List with multiline elements
:PROPERTIES:
:ID: 07-list-with-multiline-elements
:CREATED: [2020-01-01 Wed 01:01]
:END:
- This is a list item...
that spans multiple lines
- This is another list item...
that has content on multiple lines
Text after a multiline element
- This is another
multiline list
#+begin_quote
With a block element inside
#+end_quote

View File

@ -16,18 +16,3 @@
| Content2-1 | Content2-2 | Content2-3 | | Content2-1 | Content2-2 | Content2-3 |
Content after the table. Content after the table.
** Indented table
:PROPERTIES:
:ID: 10-table-test-id-02-indented
:CREATED: [2020-01-01 Wed 01:01]
:END:
- This table is indented inside a list item.
- Item before in list
| Header1 | Header2 | Header3 |
|------------+------------+------------|
| Content1-1 | Content1-2 | Content1-3 (last cell unclosed)
| Content2-1 | Content2-2 | Content2-3 |
- Item after in list
- This item happens after the indented table.

View File

@ -1,16 +0,0 @@
#+TITLE: 11-Nested lists
#+DESCRIPTION: Simple org file to test nested lists
#+TODO: TODO(t) PAUSED(p) | DONE(d)
* Nested lists
:PROPERTIES:
:ID: 11-nested-lists
:CREATED: [2020-01-01 Wed 01:01]
:END:
- 1
- 1.1
- 1.2
- 2
- 2.1
- 2.2
- 3

View File

@ -4,8 +4,7 @@ import unittest
from datetime import date from datetime import date
from datetime import datetime as DT from datetime import datetime as DT
from org_rw import MarkerToken, MarkerType, Timestamp, dumps, load, loads, dom from org_rw import MarkerToken, MarkerType, Timestamp, dumps, load, loads
import org_rw
from utils.assertions import (BOLD, CODE, HL, ITALIC, SPAN, STRIKE, UNDERLINED, from utils.assertions import (BOLD, CODE, HL, ITALIC, SPAN, STRIKE, UNDERLINED,
VERBATIM, WEB_LINK, Doc, Tokens) VERBATIM, WEB_LINK, Doc, Tokens)
@ -434,14 +433,13 @@ class TestSerde(unittest.TestCase):
doc = load(f) doc = load(f)
snippets = list(doc.get_code_snippets()) snippets = list(doc.get_code_snippets())
self.assertEqual(len(snippets), 3) self.assertEqual(len(snippets), 2)
self.assertEqual( self.assertEqual(
snippets[0].content, snippets[0].content,
'echo "This is a test"\n' 'echo "This is a test"\n'
+ 'echo "with two lines"\n' + 'echo "with two lines"\n'
+ "exit 0 # Exit successfully", + "exit 0 # Exit successfully",
) )
self.assertEqual(snippets[0].arguments.split(), ['shell', ':results', 'verbatim'])
self.assertEqual( self.assertEqual(
snippets[0].result, snippets[0].result,
"This is a test\n" + "with two lines", "This is a test\n" + "with two lines",
@ -457,14 +455,6 @@ class TestSerde(unittest.TestCase):
snippets[1].result, "This is another test\n" + "with two lines too" snippets[1].result, "This is another test\n" + "with two lines too"
) )
self.assertEqual(
snippets[2].content,
'/* This code has to be escaped to\n'
+ ' * avoid confusion with new headlines.\n'
+ ' */\n'
+ 'main(){}',
)
def test_mimic_write_file_05(self): def test_mimic_write_file_05(self):
with open(os.path.join(DIR, "05-dates.org")) as f: with open(os.path.join(DIR, "05-dates.org")) as f:
orig = f.read() orig = f.read()
@ -561,7 +551,7 @@ class TestSerde(unittest.TestCase):
MarkerToken(closing=False, tok_type=MarkerType.UNDERLINED_MODE), MarkerToken(closing=False, tok_type=MarkerType.UNDERLINED_MODE),
"markup", "markup",
MarkerToken(closing=True, tok_type=MarkerType.UNDERLINED_MODE), MarkerToken(closing=True, tok_type=MarkerType.UNDERLINED_MODE),
".", "\n" ".",
], ],
) )
@ -577,7 +567,7 @@ class TestSerde(unittest.TestCase):
self.assertEqual(lists2[0][0].counter, "1") self.assertEqual(lists2[0][0].counter, "1")
self.assertEqual(lists2[0][0].counter_sep, ".") self.assertEqual(lists2[0][0].counter_sep, ".")
self.assertEqual(lists2[0][1].content, ["Second element", "\n"]) self.assertEqual(lists2[0][1].content, ["Second element"])
self.assertEqual(lists2[0][1].counter, "2") self.assertEqual(lists2[0][1].counter, "2")
self.assertEqual(lists2[0][1].counter_sep, ".") self.assertEqual(lists2[0][1].counter_sep, ".")
@ -585,24 +575,10 @@ class TestSerde(unittest.TestCase):
self.assertEqual(lists2[1][0].counter, "1") self.assertEqual(lists2[1][0].counter, "1")
self.assertEqual(lists2[1][0].counter_sep, ")") self.assertEqual(lists2[1][0].counter_sep, ")")
self.assertEqual(lists2[1][1].content, ["Second element", "\n"]) self.assertEqual(lists2[1][1].content, ["Second element"])
self.assertEqual(lists2[1][1].counter, "2") self.assertEqual(lists2[1][1].counter, "2")
self.assertEqual(lists2[1][1].counter_sep, ")") self.assertEqual(lists2[1][1].counter_sep, ")")
hl4 = doc.getTopHeadlines()[3]
# ...
lists4 = hl4.getLists()
print(lists4)
self.assertEqual(len(lists4), 2)
self.assertEqual(lists4[0][0].content, ["This is a list item...", "\n that spans multiple lines", "\n"])
self.assertEqual(lists4[0][0].bullet, "-")
self.assertEqual(lists4[0][1].content, ["This is another list item...", "\n that has content on multiple lines", "\n"])
self.assertEqual(lists4[0][1].bullet, "-")
self.assertEqual(lists4[1][0].content, ["This is another", "\n multiline list", "\n"])
self.assertEqual(lists4[1][0].bullet, "-")
def test_org_roam_07(self): def test_org_roam_07(self):
with open(os.path.join(DIR, "07-org-roam-v2.org")) as f: with open(os.path.join(DIR, "07-org-roam-v2.org")) as f:
orig = f.read() orig = f.read()
@ -682,99 +658,3 @@ class TestSerde(unittest.TestCase):
self.assertEqual(first_table[0].cells[1].strip(), 'Header2') self.assertEqual(first_table[0].cells[1].strip(), 'Header2')
self.assertEqual(first_table[0].cells[2].strip(), 'Header3') self.assertEqual(first_table[0].cells[2].strip(), 'Header3')
hl = hl.children[0]
tables = hl.get_tables()
first_table = tables[0]
self.assertEqual(len(first_table), 4)
print(first_table[0])
self.assertEqual(len(first_table[0].cells), 3)
self.assertEqual(first_table[0].cells[0].strip(), 'Header1')
self.assertEqual(first_table[0].cells[1].strip(), 'Header2')
self.assertEqual(first_table[0].cells[2].strip(), 'Header3')
def test_tables_html_file_10(self):
with open(os.path.join(DIR, "10-tables.org")) as f:
doc = load(f)
hl = doc.getTopHeadlines()[0]
tree = hl.as_dom()
non_props = [
item
for item in tree
if not isinstance(item, dom.PropertyDrawerNode)
]
self.assertTrue(isinstance(non_props[0], dom.Text)
and isinstance(non_props[1], dom.TableNode)
and isinstance(non_props[2], dom.Text),
'Expected <Text><Table><Text>')
hl = hl.children[0]
tree = hl.as_dom()
non_props = [
item
for item in tree
if not (isinstance(item, dom.PropertyDrawerNode)
or isinstance(item, dom.Text))
]
print_tree(non_props)
self.assertTrue(len(non_props) == 1,
'Expected <List>, with only (1) element')
def test_nested_lists_html_file_11(self):
with open(os.path.join(DIR, "11-nested-lists.org")) as f:
doc = load(f)
hl = doc.getTopHeadlines()[0]
tree = hl.as_dom()
non_props = [
item
for item in tree
if not isinstance(item, dom.PropertyDrawerNode)
]
print_tree(non_props)
self.assertTrue((len(non_props) == 1) and (isinstance(non_props[0], dom.ListGroupNode)),
'Expected only <List> as top level')
dom_list = non_props[0]
children = dom_list.children
self.assertTrue(len(children) == 5, 'Expected 5 items inside <List>, 3 texts and 2 sublists')
# Assert texts
self.assertEqual(children[0].content, ['1'])
self.assertEqual(children[2].content, ['2'])
self.assertEqual(children[4].content[0], '3') # Might be ['3', '\n'] but shouldn't be a breaking change
# Assert lists
self.assertTrue(isinstance(children[1], dom.ListGroupNode), 'Expected sublist inside "1"')
self.assertEqual(children[1].children[0].content, ['1.1'])
self.assertEqual(children[1].children[1].content, ['1.2'])
self.assertTrue(isinstance(children[3], dom.ListGroupNode), 'Expected sublist inside "2"')
self.assertEqual(children[3].children[0].content, ['2.1'])
self.assertEqual(children[3].children[1].content, ['2.2'])
def print_tree(tree, indentation=0, headline=None):
for element in tree:
print(" " * indentation * 2, "EL:", element)
if "children" in dir(element):
if len(element.children) > 0:
print_element(element.children, indentation + 1, headline)
print()
elif "content" in dir(element):
for content in element.content:
print_element(content, indentation + 1, headline)
def print_element(element, indentation, headline):
if isinstance(element, org_rw.Link):
print(" " * indentation * 2, "Link:", element.get_raw())
elif isinstance(element, str):
print(" " * indentation * 2, "Str[" + element.replace('\n', '<NL>') + "]", type(element))
else:
print_tree(element, indentation, headline)