It has been replaced by Chapter and Lesson. Moved the section_parser from lms_topic directory to the lms.
85 lines
2.3 KiB
Python
85 lines
2.3 KiB
Python
"""Utility to split the text in the topic into multiple sections.
|
|
|
|
{{ section(type="example", id="foo") }}
|
|
circle(100, 100, 50)
|
|
{{ end }}
|
|
|
|
"""
|
|
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
import re
|
|
from typing import List, Tuple, Dict, Iterator
|
|
|
|
RE_SECTION = re.compile(r"^\{\{\s(\w+)\s*(?:\((.*)\))?\s*\}\}\s*")
|
|
class SectionParser:
|
|
def parse(self, text: str) -> Iterator[Section]:
|
|
"""Parses given text into sections and return an iterator over sections.
|
|
"""
|
|
lines = text.splitlines()
|
|
marked_lines = self.parse_lines(lines)
|
|
return self.group_sections(marked_lines)
|
|
|
|
def parse_lines(self, lines: List[str]) -> List[Tuple[str, str, str]]:
|
|
for line in lines:
|
|
m = RE_SECTION.match(line)
|
|
if m:
|
|
yield m.group(1), self.parse_attrs(m.group(2)), None
|
|
else:
|
|
yield None, None, line
|
|
|
|
def parse_attrs(self, attrs_str: str) -> Dict[str, str]:
|
|
# XXX-Anand: Hack
|
|
code = "dict({})".format(attrs_str or "")
|
|
return eval(code)
|
|
|
|
def group_sections(self, marked_lines) -> Iterator[Section]:
|
|
index = 0
|
|
|
|
def make_section(type='text', id=None, label=None, **attrs):
|
|
nonlocal index
|
|
index += 1
|
|
|
|
id = id or f"section-{index}"
|
|
label = label or id
|
|
return Section(
|
|
type=type,
|
|
id=id,
|
|
label=label,
|
|
attrs=attrs)
|
|
|
|
section = make_section("text")
|
|
|
|
for mark, attrs, line in marked_lines:
|
|
if not mark:
|
|
section.append(line)
|
|
continue
|
|
|
|
yield section
|
|
|
|
if mark == 'end':
|
|
section = make_section(type='text')
|
|
else:
|
|
section = make_section(**attrs)
|
|
|
|
yield section
|
|
|
|
@dataclass
|
|
class Section:
|
|
"""One section of the Topic.
|
|
"""
|
|
type: str
|
|
id: str
|
|
label: str
|
|
contents: str = ""
|
|
attrs: dict = None
|
|
|
|
def append(self, line):
|
|
if not line.endswith("\n"):
|
|
line = line + "\n"
|
|
self.contents += line
|
|
|
|
def __repr__(self):
|
|
attrs = dict(type=self.type, id=self.id, label=self.label, **self.attrs)
|
|
attrs_str = ", ".join(f'{k}="{v}"' for k, v in attrs.items())
|
|
return f'<Section({attrs_str})>'
|