Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more Markdown backends #179

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,5 @@ Exceptions to this license include the fonts in `static/fonts`, which are licens

The Bytemark name and logo (`static/images/bytemark.png`) are registered trademarks of Bytemark Limited.

[tag-previous]: https://github.com/HackSoc/hacksoc.org/tree/08694ad0fd706c4ff4580303a97031452d73772d
[tag-previous]: https://github.com/HackSoc/hacksoc.org/tree/node-last
[tag-hackyll]: https://github.com/HackSoc/hacksoc.org/tree/hakyll-last
64 changes: 59 additions & 5 deletions docs/adding_features_python.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ NB: The Jinja documentation uses the term "template" to refer to any of:
[URL generators](https://pythonhosted.org/Frozen-Flask/#url-generators) should only be used for files that aren't intended to be part of the main site, or are intended to be "unlisted". If there's no chain of links from the main page to another page, then you can't really expect anyone to find that page organically. Implementing a URL generator just requires adding a Python function that calls `yield` with each of the routes you want to ensure are rendered, and decorating the function with `@freezer.register_generator`.

## Modifying the Markdown handler
All things Markdown are hidden away in `markdown.py` so the rest of the package doesn't have to worry about it. It exports a single function, `render_markdown` which takes a Markdown source string and returns a rendered HTML string. Even if this wraps a single function from a Markdown library, if that library ever changes in the future it means that the codebase only needs to be changed in one place.
All things Markdown are hidden away in `markdown/__init__.py` so the rest of the `hacksoc_org` package doesn't have to worry about it. It exports a single function, `render_markdown` which takes a Markdown source string and returns a rendered HTML string. Even if this wraps a single function from a Markdown library, if that library ever changes in the future it means that the codebase only needs to be changed in one place.

Currently the website uses [`python-markdown2`][pymd2] and loads the following extras:
- `fenced-code-blocks` allow blocks of code to be placed between triple-backticks (\`\`\`)
Expand All @@ -46,20 +46,74 @@ Since the server READMEs use fenced code blocks and AGMs will often use many tab
### Choice of Markdown libraries
Choosing a Markdown backend is not straightforward; implementations vary in their interpretation of the spec (Gruber's `markdown.pl` or the less ambiguous CommonMark standard) and their extra features (tables, code block highlighting, smart quotes). Currently [`markdown2`][pymd2] is used, although its non-conformance with CommonMark makes a replacement desireable.

To help test between Markdown backends, non-default backends can be selected with the `--markdown` command-line option. Only [`cmark`](https://github.com/commonmark/cmark) is available (provided through the [`cmarkgfm`](https://github.com/theacodes/cmarkgfm) Python bindings).
To help test between Markdown backends, non-default backends can be selected with the `--markdown` command-line option.

```
# Equivalent; markdown2 is the default backend
hacksoc_org run
hacksoc_org run --markdown markdown2
hacksoc_org run --markdown markdown2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super minor nitpick

Suggested change
hacksoc_org run --markdown markdown2
hacksoc_org run --markdown markdown2


# Use cmark instead
# Use an alternative instead
hacksoc_org run --markdown cmark
hacksoc_org run --markdown commonmark
hacksoc_org run --markdown mistletoe
hacksoc_org run --markdown markdown-it

# this works with all subcommands
hacksoc_org freeze --markdown cmark
hacksoc_org freeze --markdown cmark

# in any order
hacksoc_org --markdown cmark run
```
#### Markdown2 (Current default)
Comment on lines +67 to +68
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
#### Markdown2 (Current default)
```
#### Markdown2 (Current default)

[GitHub](https://github.com/trentm/python-markdown2/wiki)

Provides syntax highlighting via Pygments. Aims to conform to Gruber's Markdown rather than CommonMark.

#### Cmark
GitHub ([Python bindings](https://github.com/theacodes/cmarkgfm), [C implementation](https://github.com/github/cmark-gfm))

Fork of the CommonMark reference implementation, maintained by GitHub to provide [GFM](https://github.github.com/gfm/) features. Only provides syntax highlighing for the client-side, by adding a (eg.) `lang="py"` attribute to `<pre>` blocks for a JavaScript library to parse and highlight.
#### CommonMark
Comment on lines +76 to +77
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Fork of the CommonMark reference implementation, maintained by GitHub to provide [GFM](https://github.github.com/gfm/) features. Only provides syntax highlighing for the client-side, by adding a (eg.) `lang="py"` attribute to `<pre>` blocks for a JavaScript library to parse and highlight.
#### CommonMark
Fork of the CommonMark reference implementation, maintained by GitHub to provide [GFM](https://github.github.com/gfm/) features. Only provides syntax highlighing for the client-side, by adding a (eg.) `lang="py"` attribute to `<pre>` blocks for a JavaScript library to parse and highlight.
#### CommonMark

[GitHub](https://github.com/readthedocs/commonmark.py)

Python port of CommonMark.js, maintained by readthedocs. Provides no syntax highlighting out-of-the-box, but has been added with [`commonmark_pygments_renderer.py`](../hacksoc_org/markdown/commonmark_pygments_renderer.py).

**Does not support tables**.
#### Mistletoe
Comment on lines +82 to +83
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Does not support tables**.
#### Mistletoe
**Does not support tables**.
#### Mistletoe

[GitHub](https://github.com/miyuchina/mistletoe)

Gives an example integration of Pygments for syntax highlighing, adapted into [`mistletoe_pygments_renderer.py`](../hacksoc_org/markdown/mistletoe_pygments_renderer.py)
#### Markdown-it
Comment on lines +86 to +87
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Gives an example integration of Pygments for syntax highlighing, adapted into [`mistletoe_pygments_renderer.py`](../hacksoc_org/markdown/mistletoe_pygments_renderer.py)
#### Markdown-it
Gives an example integration of Pygments for syntax highlighing, adapted into [`mistletoe_pygments_renderer.py`](../hacksoc_org/markdown/mistletoe_pygments_renderer.py)
#### Markdown-it

[GitHub](https://github.com/executablebooks/markdown-it-py)

Complicated architecture. Syntax highlighing added with Pygments in [`markdownit_pygments_highlighter.py`](../hacksoc_org/markdown/markdownit_pygments_highlighter.py).

```html
<!-- Extra markup added here by Markdown-it -->
<pre>
<code class="language-py">
<!-- -->
<div class="codehilite">
<pre>
<span></span>
<code>

<!-- Other Pygments uses -->
<div class="codehilite">
<pre>
<span></span>
<code>

```

#### Others
There are many more CommonMark-comforming backends that aren't enabled (yet). They include:

- [Mistune](https://github.com/lepture/mistune)
- Doesn't provide syntax highlighing, but could be added by overriding HTMLRenderer::block_code
- Not [strictly](https://github.com/miyuchina/mistletoe#performance) CommonMark compliant


## Serving Flask in production
Some of Flask's extra power (handling POST requests, HTTP redirects) require it to be run in production (as opposed to generating HTML files and serving those from a static web server). Currently the [configuration](../.flaskenv) of Flask puts it into debug mode. This is extremely unsafe to run in production. Secondly, `hacksoc_org run` or `app.run()` should not be used in production as it used Flask's built-in development server, which is not suitable for production use even when debug mode is disabled. Instead, consult [Flask's documentation](https://flask.palletsprojects.com/en/2.0.x/deploying/#self-hosted-options) on options for WSGI and CGI servers.
Expand Down
3 changes: 3 additions & 0 deletions hacksoc_org/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
app = flask.Flask(__name__, static_folder=None, template_folder=None)
# these folders are defined in the Blueprint anyway
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config["ENV"] = "development"
app.config["DEBUG"] = True


app.jinja_env.add_extension("jinja2.ext.do")
# adds support for the jinja "do" statement
Expand Down
19 changes: 12 additions & 7 deletions hacksoc_org/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from hacksoc_org.consts import *
from hacksoc_org.freeze import freeze
from hacksoc_org.serve import serve
from hacksoc_org.markdown import implementations, get_backend_help

import argparse

Expand All @@ -18,13 +19,11 @@ def inner(fn):


def main(args=None):
parser = argparse.ArgumentParser(
allow_abbrev=False,
epilog="""
epilog = """
SUBCOMMANDS

run
Starts a local development server on https://localhost:5000/. Automatically
Starts a local development server on http://localhost:5000/. Automatically
reloads when templates or Python code is changed. Recommended while
developing pages or features.

Expand All @@ -36,11 +35,17 @@ def main(args=None):

serve
Calls `freeze` then starts a local HTTP server from `build/` on
https://localhost:5000/. Will not automatically rebuild the website on
http://localhost:5000/. Will not automatically rebuild the website on
content change, you will need to re-run `serve`. Recommended to use this at
least once to check that a) new content is part of the "frozen" site and b)
no errors occur in freezing the site.
""".strip(),
""".strip()

epilog += "\n\n" + get_backend_help()

parser = argparse.ArgumentParser(
allow_abbrev=False,
epilog=epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
)

Expand All @@ -50,7 +55,7 @@ def main(args=None):

parser.add_argument(
"--markdown",
choices=["markdown2", "cmark"],
choices=list(implementations.keys()),
default="markdown2",
help="Markdown backend to use (default markdown2)",
)
Expand Down
71 changes: 0 additions & 71 deletions hacksoc_org/markdown.py

This file was deleted.

Loading