#!/usr/bin/python3 import argparse import os import pypandoc import re import sys import yaml import fragments root = "" lang = "de" # 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(os.path.join(root, 'layouts/root.html'), 'r').read() wrapper = wrapper.replace('@slides', compile_chapters()) wrapper = insert_metadata(wrapper, lang=lang) wrapper = fragments.defragmentize(wrapper) with open(os.path.join(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
s. def compile_chapters(): structure = read_yaml('slides.yml') chapters = "" for chapter in structure: chapters += '
\n' + compile_chapter(chapter) + '\n
' 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
s. def compile_chapter(chapter): global root if type(chapter) != str: raise Exception('Chapters with attributes are not supported yet.\n' + str(chapter)) chapter_file = open(os.path.join(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 += '
\n' + compile_slide(slide) + '\n
\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"

(.+?)

\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): global root try: return open(os.path.join(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): filters = [] pdoc_args = [ '--mathjax', # Preparing formulas '--smart' # Smart typography (dashes, ellipses, …) ] return pypandoc.convert_text( content, 'html', format='md', extra_args=pdoc_args, filters=filters) # Calls a YAML parser for the given relative path inside the presentation root # directory. Returns a dictionary with the YAML content. def read_yaml(path): global root with open(os.path.join(root, path), 'r') as stream: try: return yaml.safe_load(stream) except yaml.YAMLError as exc: print(exc) # Retrieve the available languages as stated in the meta.yml (key: language). def get_available_languages(root): return read_yaml(os.path.join(root, 'meta.yml'))['language'] if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("rootdirectory", help="your project's root directory") parser.add_argument("-l", "--language", default="all", help="the presentation language (default: all)") args = parser.parse_args() if args.language == "all": for language in get_available_languages(args.rootdirectory): compile(args.rootdirectory, language=language) else: compile(args.rootdirectory, language=args.language)