Pi66

merodi
A markdown-based static site generator.
git clone https://git.pi66.xyz/merodi

← back to log

feat: reload plugins on change, force-rebuild on template edit

author: pi66
date: 2026-07-15 00:10
hash: 5159727ec9ecf0d0db2e806ec6fe137375cee553

Diffstat:

M

src/watcher.py
33 +++++++++++++++++-------------

M

src/webviewer.py
7 +++---
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
diff --git a/src/watcher.py b/src/watcher.py
index 5301220..32dda4a 100644
--- a/src/watcher.py
+++ b/src/watcher.py
@@ -4,15 +4,14 @@ from watchdog.observers import Observer
 from watchdog.events import FileSystemEventHandler
 import time

-from src import settings
 from .config import find_project_from_path, load_config
-from .build import compile_md_to_html
-from .log import  warn
+from .build import compile_file, load_plugins
+from .log import warn
 from .errors import fatal

 current_md_file = None

-def reload(changed_path, tree_config):
+def reload(changed_path, config, plugins, force=None):
     global current_md_file
     try:
         if changed_path.endswith(".md"):
@@ -20,35 +19,41 @@ def reload(changed_path, tree_config):
         if current_md_file is None:
             return None

-        md_relpath = path.relpath(current_md_file, tree_config.markdown)
+        md_relpath = path.relpath(current_md_file, config.tree.markdown)
         html = path.splitext(md_relpath)[0] + ".html"
-        dest = path.join(tree_config.dest, html)
-        compile_status = compile_md_to_html(current_md_file, dest)
+        dest = path.join(config.tree.dest, html)
+        compile_status = compile_file(current_md_file, dest, config, plugins, force=force)
         if compile_status is None:
             return None
         return html
     except Exception as e:
         warn(str(e))

-def watch_files(reload_func:Callable | None=None):
+def watch_files(config, reload_func:Callable | None=None):
     last_reload = {}
-    config = settings.CONFIG
-    
+    plugins = load_plugins(config)
     class ReloadHandler(FileSystemEventHandler):
         def on_modified(self, event):
+            nonlocal plugins
             reload_path = event.src_path
+            force = False
+            if reload_path.startswith(config.tree.templates):
+                force = True
+            if reload_path.startswith(config.tree.plugins):
+                plugins = load_plugins(config)
             if event.is_directory :
                     return
+
             now = time.time()
             last = last_reload.get(reload_path, 0)
             if now - last < 0.3:
                 return
             last_reload[reload_path] = now
-            file = reload( reload_path, config.tree)
+            file = reload( reload_path, config, plugins, force=force)
             if reload_func and file: reload_func(file)
     observer = Observer()
     handler = ReloadHandler()
-    for file in [config.tree.markdown, config.tree.templates, path.dirname(config.tree.plugins), config.tree.static]:
+    for file in [config.tree.markdown, config.tree.templates, config.tree.plugins, config.tree.static]:
         observer.schedule(
             handler,
             path=file,
@@ -61,8 +66,8 @@ def run_watcher(project_path):
         project_path = project_path if project_path else getcwd()
         find_project_from_path(project_path)
         chdir(project_path)
-        settings.CONFIG = load_config()
-        observers = watch_files()
+        config = load_config()
+        observers = watch_files(config)
         observers.start()
         try:
             while True:
diff --git a/src/webviewer.py b/src/webviewer.py
index 40e359b..0c6339d 100644
--- a/src/webviewer.py
+++ b/src/webviewer.py
@@ -4,6 +4,7 @@ from threading import Thread
 import webview

 from src import settings
+from src.build import load_plugins

 from .config import find_project_from_path, load_config
 from .errors import fatal, html_fatal
@@ -74,7 +75,7 @@ def http_server(host, port, routes):
         def log_message(self, format, *args):
             try:
                 method, path, _ = args[0].split(" ", 2)
-                info(f"{method} {path} {args[1]}")
+                info(f"{method} {path} {args[1]}", title="HTTP")
             except (ValueError, IndexError):
                 info(format % args)

@@ -94,8 +95,7 @@ def run(project_path):
         project_path = project_path if project_path else getcwd()
         find_project_from_path(project_path)
         chdir(project_path)
-        settings.CONFIG = load_config()
-        config = settings.CONFIG
+        config = load_config()
         host = config.webview.host
         port = config.webview.port
         routes = {
@@ -120,6 +120,7 @@ def run(project_path):

         window = webview.create_window("Merodi", url=f"http://{_ip_cache[0]}:{port}/")
         observer = watch_files(
+                config,
                 lambda path: reload_webview(window, path, _ip_cache[0], port),
                 )
         observer.start()