diff --git a/rophako/utils.py b/rophako/utils.py index 22ebfee..b6004e3 100644 --- a/rophako/utils.py +++ b/rophako/utils.py @@ -57,30 +57,71 @@ def template(name, **kwargs): def markdown_template(path): - """Render a Markdown page to the browser.""" + """Render a Markdown page to the browser. + + The first line in the Markdown page should be an H1 header beginning with + the # sign. This will set the page's to match the header value. + + Pages can include lines that begin with the keyword `:meta` to apply + meta information to control the Markdown parser. Supported meta lines + and examples: + + To 'blacklist' extensions, i.e. to turn off line breaks inside a paragraph + getting translated into a <br> tag (the key is the minus sign): + :meta extensions -nl2br + + To add an extension, i.e. the abbreviations from PHP Markdown Extra: + :meta extensions abbr""" # The path is the absolute path to the Markdown file, so open it directly. fh = codecs.open(path, "r", "utf-8") body = fh.read() fh.close() + # Look for meta information in the file. + lines = body.split("\n") + content = list() # New set of lines, without meta info. + extensions = set() + blacklist = set() # Blacklisted extensions + for line in lines: + if line.startswith(":meta"): + parts = line.split(" ") + if len(parts) >= 3: + # Supported meta commands. + if parts[1] == "extensions": + # Extension toggles. + for extension in parts[2:]: + if extension.startswith("-"): + extension = extension[1:] + blacklist.add(extension) + else: + extensions.add(extension) + else: + content.append(line) + # Extract a title from the first line. - first = body.split("\n")[0] + first = content[0] if first.startswith("#"): first = first[1:].strip() - rendered = render_markdown(body) + rendered = render_markdown("\n".join(content), + extensions=extensions, + blacklist=blacklist, + ) return template("markdown.inc.html", title=first, markdown=rendered, ) -def render_markdown(body, html_escape=True): +def render_markdown(body, html_escape=True, extensions=None, blacklist=None): """Render a block of Markdown text. This will default to escaping literal HTML characters. Set - `html_escape=False` to trust HTML.""" + `html_escape=False` to trust HTML. + + * extensions should be a set() of extensions to add. + * blacklist should be a set() of extensions to blacklist.""" args = dict( lazy_ol=False, # If a numbered list starts at e.g. 4, show the <ol> there @@ -101,6 +142,14 @@ def render_markdown(body, html_escape=True): if html_escape: args["safe_mode"] = "escape" + # Additional extensions? + if extensions is not None: + for ext in extensions: + args["extensions"].append(ext) + if blacklist is not None: + for ext in blacklist: + args["extensions"].remove(str(ext)) + return markdown.markdown(body, **args) @@ -157,4 +206,4 @@ def sanitize_name(name): """Sanitize a name that may be used in the filesystem. Only allows numbers, letters, and some symbols.""" - return re.sub(r'[^A-Za-z0-9 .\-_]+', '', name) \ No newline at end of file + return re.sub(r'[^A-Za-z0-9 .\-_]+', '', name)