Skip to content

Instantly share code, notes, and snippets.

@kamilkrzyskow
Created November 13, 2025 16:58
Show Gist options
  • Select an option

  • Save kamilkrzyskow/72c6ec3093e48132ead9469558e144c2 to your computer and use it in GitHub Desktop.

Select an option

Save kamilkrzyskow/72c6ec3093e48132ead9469558e144c2 to your computer and use it in GitHub Desktop.
Zensical with extra hooks
"""Zensical with extra hooks
Run with `python script.py [Zensical-OPTIONS]`
For the initial run, and after any script changes run with `build --clean` first.
Added wrappers for functions that are called back from Rust runtime.
This allows to partially mimic the following events from MkDocs:
- on_config
- on_page_markdown
- on_page_content
If a hook or plugin had its core logic in any of these events, it could be possible
to port it over here before the module system arrives. Most frequent use cases are probably meta
manipulation, update of config.extra, markdown placeholder replacement etc. all this is possible now.
File management is done purely in Rust, and no signal/status about it is sent to Python.
Tested with v0.0.7, the Python API should be stable, I don't expect major changes in the future outside of Rust.
This modification is not endorsed by Zensical Team, so don't report any bugs while using it.
I ask kindly... :)
MIT License 2025 Kamil Krzyśków (HRY)
"""
import zensical.config as config_module
import zensical.main as main_module
import zensical.markdown as markdown_module
from zensical.config import parse_config
from zensical.markdown import render as markdown_render
def main():
print("Time to hack")
markdown_module.render = wrap_markdown(markdown_render)
config_module.parse_config = wrap_config(parse_config)
main_module.cli()
def wrap_config(func):
def wrapper(path: str) -> dict:
# Load "Config" struct
config = func(path)
print("Config was loaded")
# on_config event
# replace values in config dict
# code ...
# extra = config["extra"]
# extra["custom_key"] = "Custom Key"
# sync global _CONFIG between modules
config_module._CONFIG = config
markdown_module._CONFIG = config
return config
return wrapper
def wrap_markdown(func):
def wrapper(content: str, path: str) -> dict:
# on_page_markdown event
# modify content string at this stage it includes the meta header
# meta is not extracted yet
# code ...
# content += "\n---\nTEST"
# content = content.replace("oldtext", "newtext")
# process markdown file and prepare "Page" struct
result = func(content, path)
print("Markdown processed", path)
# on_page_content event
# replace meta, content, etc. in the result dict
# before rendering the page with the template files
# result["meta"]["title"] = "Replaced Title"
# code ...
return result
return wrapper
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment