diff --git a/.gitattributes b/.gitattributes index bf92e559..d9d23f9b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,3 +7,4 @@ mkdocs/themes/readthedocs/js/** linguist-vendored mkdocs/themes/readthedocs/js/theme.js linguist-vendored=false mkdocs/themes/readthedocs/css/** linguist-vendored mkdocs/themes/readthedocs/css/theme_extra.css linguist-vendored=false +docs/img/plugin-events.svg linguist-generated diff --git a/docs/css/extra.css b/docs/css/extra.css index 6c6739bb..3dce20dd 100644 --- a/docs/css/extra.css +++ b/docs/css/extra.css @@ -30,6 +30,12 @@ dd { padding-left: 20px; } +.card-body svg { + width: 100%; + padding: 0 50px; + height: auto; +} + /* Homepage */ body.homepage div.jumbotron { diff --git a/docs/dev-guide/plugins.md b/docs/dev-guide/plugins.md index b7845b3b..5ee045b1 100644 --- a/docs/dev-guide/plugins.md +++ b/docs/dev-guide/plugins.md @@ -139,6 +139,24 @@ All `BasePlugin` subclasses contain the following method(s): There are three kinds of events: [Global Events], [Page Events] and [Template Events]. +
+ + See a diagram with relations between all the plugin events + +
+ +--8<-- "docs/img/plugin-events.svg" +
+
+
+ #### Global Events Global events are called once per build at either the beginning or end of the diff --git a/docs/img/plugin-events.py b/docs/img/plugin-events.py new file mode 100644 index 00000000..b98691dd --- /dev/null +++ b/docs/img/plugin-events.py @@ -0,0 +1,169 @@ +# Run this to re-generate 'plugin-events.svg'. +# Requires `pip install graphviz`. + +import contextlib +import pathlib +import re + +from graphviz import Digraph + + +g = Digraph("MkDocs", format="svg") +g.attr(compound="true", bgcolor="transparent") +g.graph_attr.update(fontname="inherit", tooltip=" ") +g.node_attr.update(fontname="inherit", tooltip=" ", style="filled") +g.edge_attr.update(fontname="inherit", tooltip=" ") + + +def strip_suffix(name): + return re.sub(r"_.$", "", name) + + +subgraph_to_first_node = {} +subgraph_to_last_node = {} + + +def node(g, name, **kwargs): + if "_point" in name: + kwargs.setdefault("shape", "point") + else: + kwargs.setdefault("fillcolor", "#77ff7788") + kwargs.setdefault("color", "#00000099") + kwargs.setdefault("label", strip_suffix(name)) + + g.node(name, **kwargs) + + subgraph_to_first_node.setdefault(g.name, name) + subgraph_to_last_node[g.name] = name + + +def edge(g, a, b, dashed=False, **kwargs): + if kwargs.get("style") == "dashed": + kwargs.setdefault("penwidth", "1.5") + + if a in subgraph_to_last_node: + kwargs.setdefault("ltail", a) + a = subgraph_to_last_node[a] + if b in subgraph_to_first_node: + kwargs.setdefault("lhead", b) + b = subgraph_to_first_node[b] + + if a.startswith(("on_", "placeholder_")): + a += ":s" + else: + node(g, a.split(":")[0]) + if b.startswith(("on_", "placeholder_")): + b += ":n" + else: + node(g, b.split(":")[0]) + + g.edge(a, b, **kwargs) + + +def ensure_order(a, b): + edge(g, a, b, style="invis") + + +@contextlib.contextmanager +def cluster(g, name, **kwargs): + assert name.startswith("cluster_") + kwargs.setdefault("label", strip_suffix(name)[len("cluster_") :]) + kwargs.setdefault("bgcolor", "#dddddd55") + kwargs.setdefault("pencolor", "#00000066") + with g.subgraph(name=name) as c: + c.attr(**kwargs) + yield c + + +def event(g, name, parameters): + with cluster( + g, f"cluster_{name}", href=f"#{name}", bgcolor="#ffff3388", pencolor="#00000088" + ) as c: + label = "|".join(f"<{p}>{p}" for p in parameters.split()) + node(c, name, shape="record", label=label, fillcolor="#ffffff55") + + +def placeholder_cluster(g, name): + with cluster(g, name) as c: + node(c, f"placeholder_{name}", label="...", fillcolor="transparent", color="transparent") + + +event(g, "on_config", "config") +event(g, "on_pre_build", "config") +event(g, "on_files", "files config") +event(g, "on_nav", "nav config files") + +edge(g, "load_config", "on_config:config") +edge(g, "on_config:config", "on_pre_build:config") +edge(g, "on_config:config", "get_files") +edge(g, "get_files", "on_files:files") +edge(g, "on_files:files", "get_nav") +edge(g, "get_nav", "on_nav:nav") +edge(g, "on_files:files", "on_nav:files") + +with cluster(g, "cluster_populate_page") as c: + event(c, "on_pre_page", "page config files") + event(c, "on_read_source", "page config") + event(c, "on_page_markdown", "markdown page config files") + event(c, "on_page_content", "html page config files") + + edge(c, "on_pre_page:page", "on_read_source:page", style="dashed") + edge(c, "cluster_on_read_source", "on_page_markdown:markdown", style="dashed") + edge(c, "on_page_markdown:markdown", "render_p", style="dashed") + edge(c, "render_p", "on_page_content:html", style="dashed") + +edge(g, "on_nav:files", "pages_point_a", arrowhead="none") +edge(g, "pages_point_a", "on_pre_page:page", style="dashed") +edge(g, "pages_point_a", "cluster_populate_page") + +for i in 2, 3: + placeholder_cluster(g, f"cluster_populate_page_{i}") + edge(g, "pages_point_a", f"cluster_populate_page_{i}", style="dashed") + edge(g, f"cluster_populate_page_{i}", "pages_point_b", style="dashed") + + +event(g, "on_env", "env config files") + +edge(g, "on_page_content:html", "pages_point_b", style="dashed") +edge(g, "pages_point_b", "on_env:files") + + +edge(g, "pages_point_b", "pages_point_c", arrowhead="none") +edge(g, "pages_point_c", "on_page_context:page", style="dashed") + +with cluster(g, "cluster_build_page") as c: + event(c, "on_page_context", "context page config nav") + event(c, "on_post_page", "output page config") + + edge(c, "get_context", "on_page_context:context") + edge(c, "on_page_context:context", "render") + edge(c, "get_template", "render") + edge(c, "render", "on_post_page:output") + edge(c, "on_post_page:output", "write_file") + + +edge(g, "on_nav:nav", "cluster_build_page") +edge(g, "on_env:env", "cluster_build_page") + +for i in 2, 3: + placeholder_cluster(g, f"cluster_build_page_{i}") + edge(g, "pages_point_c", f"cluster_build_page_{i}", style="dashed") + + +event(g, "on_post_build", "config") +event(g, "on_serve", "server config") + + +ensure_order("on_pre_build", "on_files") +ensure_order("on_nav", "cluster_populate_page") +ensure_order("cluster_populate_page_2", "cluster_populate_page_3") +ensure_order("on_page_content", "on_env") +ensure_order("pages_point_c", "cluster_build_page") +ensure_order("cluster_build_page_2", "cluster_build_page_3") +ensure_order("cluster_build_page", "on_post_build") +ensure_order("on_post_build", "on_serve") + + +data = g.pipe() +data = data[data.index(b" + +MkDocs + + + + +cluster_on_config + + +on_config + + + + +cluster_on_pre_build + + +on_pre_build + + + + +cluster_on_files + + +on_files + + + + +cluster_on_nav + + +on_nav + + + + +cluster_populate_page + + +populate_page + + + + +cluster_on_pre_page + + +on_pre_page + + + + +cluster_on_read_source + + +on_read_source + + + + +cluster_on_page_markdown + + +on_page_markdown + + + + +cluster_on_page_content + + +on_page_content + + + + +cluster_on_env + + +on_env + + + + +cluster_populate_page_2 + + +populate_page + + + + +cluster_populate_page_3 + + +populate_page + + + + +cluster_build_page + + +build_page + + + + +cluster_on_page_context + + +on_page_context + + + + +cluster_on_post_page + + +on_post_page + + + + +cluster_build_page_2 + + +build_page + + + + +cluster_build_page_3 + + +build_page + + + + +cluster_on_post_build + + +on_post_build + + + + +cluster_on_serve + + +on_serve + + + + + +on_config + + +config + + + + + +on_pre_build + + +config + + + + + +on_config:s->on_pre_build:n + + + + + + + + +get_files + + +get_files + + + + + +on_config:s->get_files + + + + + + + + +on_files + + +files + +config + + + + + + +on_nav + + +nav + +config + +files + + + + + +on_files:s->on_nav:n + + + + + + + + +get_nav + + +get_nav + + + + + +on_files:s->get_nav + + + + + + + + +render_p + + +render + + + + + + +pages_point_a + + + + + + + +on_nav:s->pages_point_a + + + + + + + +get_context + + +get_context + + + + + +on_nav:s->get_context + + + + + + + + +load_config + + +load_config + + + + + +load_config->on_config:n + + + + + + + + +get_files->on_files:n + + + + + + + + +get_nav->on_nav:n + + + + + + + + +on_pre_page + + +page + +config + +files + + + + + +on_read_source + + +page + +config + + + + + +on_pre_page:s->on_read_source:n + + + + + + + + +on_page_markdown + + +markdown + +page + +config + +files + + + + + +on_read_source:s->on_page_markdown:n + + + + + + + + +on_page_markdown:s->render_p + + + + + + + + +on_page_content + + +html + +page + +config + +files + + + + + +pages_point_b + + + + + + + +on_page_content:s->pages_point_b + + + + + + + + +on_env + + +env + +config + +files + + + + + + +render_p->on_page_content:n + + + + + + + + +pages_point_a->on_pre_page:n + + + + + + + + +pages_point_a->render_p + + + + + + + + +placeholder_cluster_populate_page_2 + + +... + + + + + +pages_point_a->placeholder_cluster_populate_page_2:n + + + + + + + + +placeholder_cluster_populate_page_3 + + +... + + + + + +pages_point_a->placeholder_cluster_populate_page_3:n + + + + + + + + +placeholder_cluster_populate_page_2:s->pages_point_b + + + + + + + + + +pages_point_b->on_env:n + + + + + + + + +pages_point_c + + + + + + + +pages_point_b->pages_point_c + + + + + + + +placeholder_cluster_populate_page_3:s->pages_point_b + + + + + + + + +on_env:s->get_context + + + + + + + + +on_page_context + + +context + +page + +config + +nav + + + + + +pages_point_c->on_page_context:n + + + + + + + + + +placeholder_cluster_build_page_2 + + +... + + + + + +pages_point_c->placeholder_cluster_build_page_2:n + + + + + + + + +placeholder_cluster_build_page_3 + + +... + + + + + +pages_point_c->placeholder_cluster_build_page_3:n + + + + + + + + +render + + +render + + + + + +on_page_context:s->render + + + + + + + + +on_post_page + + +output + +page + +config + + + + + +write_file + + +write_file + + + + + +on_post_page:s->write_file + + + + + + + + +get_context->on_page_context:n + + + + + + + + +render->on_post_page:n + + + + + + + + +get_template + + +get_template + + + + + +get_template->render + + + + + + + + +on_post_build + + +config + + + + + + + +on_serve + + +server + +config + + + + + + diff --git a/mkdocs.yml b/mkdocs.yml index 48495b29..39cbbbfc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ markdown_extensions: permalink:  - attr_list - def_list + - pymdownx.snippets - callouts - mdx_gh_links: user: mkdocs diff --git a/requirements/project-min.txt b/requirements/project-min.txt index 6114a258..00719753 100644 --- a/requirements/project-min.txt +++ b/requirements/project-min.txt @@ -10,6 +10,7 @@ markdown-callouts==0.2 ghp-import==1.0 pyyaml_env_tag==0.1 mkdocs-redirects==1.0.1 +pymdown-extensions==8.0.1 importlib_metadata==4.3 packaging==20.5 mergedeep==1.3.4 diff --git a/requirements/project.txt b/requirements/project.txt index b409ce6c..2e1be0c8 100644 --- a/requirements/project.txt +++ b/requirements/project.txt @@ -9,6 +9,7 @@ markdown-callouts>=0.2 ghp-import>=1.0 pyyaml_env_tag>=0.1 mkdocs-redirects>=1.0.1 +pymdown-extensions>=8.0.1 importlib_metadata>=4.3 packaging>=20.5 mergedeep>=1.3.4