onpoint/main.py

122 lines
4.7 KiB
Python

#!/usr/bin/python3
import yaml
import pypandoc
import re
# Compiles a presentation in the given language from the given directory and
# stores it in a corresponding slides.lang.html file inside the same directory.
def compile(directory, language='en'):
global root
root = directory
global lang
lang = language
wrapper = open(root + 'layouts/root.html', 'r').read()
wrapper = wrapper.replace('@slides', compile_chapters())
wrapper = insert_metadata(wrapper, lang=lang)
with open(root + 'slides.' + lang + '.html', 'w+') as output:
output.write(wrapper)
print('done')
# Replaces the placeholders in the given content with corresponding values in
# the given language from the meta.yml and returns the filled content.
def insert_metadata(content, lang=None):
metadata = read_yaml('meta.yml')
for key, value in metadata.items():
placeholder = '@' + key
filler = value[lang]
print('replace', placeholder, 'with', filler)
if '@' + key in content:
content = content.replace(placeholder, filler)
return content
# Compiles a presentation's chapters (the content without the wrapper)
# according to slides.yml and returns them as one string of <section>s.
def compile_chapters():
structure = read_yaml('slides.yml')
chapters = ""
for chapter in structure:
chapters += '<section>\n' + compile_chapter(chapter) + '\n</section>'
return chapters # string
# Compiles a presentation's chapter (given its name) by splitting it into
# slides, compiling those, and returning them as a string of <article>s.
def compile_chapter(chapter):
if type(chapter) != str:
raise Exception('Chapters with attributes are not supported yet.\n' +
str(chapter))
chapter_file = open(root + 'slides/' + chapter + '.' + lang + '.md', 'r')
delimiter = '\n@slide'
chapter_input = ('\n' + chapter_file.read()).split(delimiter)
slides = [delimiter + slide for slide in chapter_input][1:]
chapter = ''
for slide in slides:
chapter += '<article>\n' + compile_slide(slide) + '\n</article>\n'
return chapter
# Compiles a single slide by splitting it up into single metadata and data
# attributes, loading them into the corresponding template, and returning the
# result.
def compile_slide(slide):
slide = slide.strip()
slide_metadata = get_slide_metadata(slide)
slide_data = get_slide_data(slide)
slide = get_slide_layout(slide_metadata['layout'])
for key, value in slide_data.items():
placeholder = '@' + key
filler = convert_slide_content(value)
print('replace', placeholder, 'with', filler)
if '@' + key in slide:
slide = slide.replace(placeholder, filler)
# very unelegant attempt at inline elements
slide = re.sub(r"<p>(.+?)</p>\n\(inline\)", r"\1", slide)
return slide
# Parses the metadata passage of a given slide and returns the metadata as a
# dictionary. For some items, default values are used if the slide does not
# contain them.
def get_slide_metadata(slide):
metadata = { 'layout': 'default' }
metadata_attributes = re.search('^@slide\((.+)\)', slide.splitlines()[0])
if metadata_attributes:
metadata_attributes = metadata_attributes.group(1).split(' ')
for attribute in metadata_attributes:
metadata[attribute.split('=')[0]] = attribute.split('=')[1]
return metadata
# Parses the data part of a given slide and returns dictionary of field names
# and corresponding raw values.
def get_slide_data(slide):
if slide.startswith('@slide'):
slide = slide[slide.find('\n')+1:] # cut off @slide declaration
slide_data = slide.strip().split('\n\n@')
slide_data = { item.split()[0].strip('@') : "\n".join(item.splitlines()[1:]) for item in slide_data }
return slide_data
# Reads the layout file for a given layout name and returns its content as a
# string.
def get_slide_layout(layout_name):
try:
return open(root + 'layouts/' + layout_name + '.html', 'r').read()
except FileNotFoundError:
raise Exception('Layout ' + layout_name + ' not found!')
# Calls the pandoc converter to convert a given Markdown string to HTML.
# Returns an HTML string.
def convert_slide_content(content):
return pypandoc.convert_text(content, 'html', format='md')
# Calls a YAML parser for the given relativ path inside the presentation root
# directory. Returns a dictionary with the YAML content.
def read_yaml(path):
with open(root + path, 'r') as stream:
try:
return yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
if __name__ == '__main__':
compile('../test/', language='de')
compile('../test/', language='en')