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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 | diff --git a/src/main.py b/src/main.py
index 3054af2..780d6fa 100755
--- a/src/main.py
+++ b/src/main.py
@@ -20,6 +20,9 @@ def main():
webview_parser = sub_parser.add_parser("webview", parents=[common])
webview_parser.add_argument("path", nargs="?")
+ webview_parser = sub_parser.add_parser("watch", parents=[common])
+ webview_parser.add_argument("path", nargs="?")
+
build_parser = sub_parser.add_parser("build", parents=[common])
build_parser.add_argument("--release", action="store_true")
build_parser.add_argument("--debug", action="store_true")
@@ -41,3 +44,7 @@ def main():
elif args.command == "webview":
from .webviewer import run
run(args.path)
+
+ elif args.command == "watch":
+ from .watcher import run_watcher
+ run_watcher(args.path)
diff --git a/src/watcher.py b/src/watcher.py
new file mode 100644
index 0000000..0b23910
--- /dev/null
+++ b/src/watcher.py
@@ -0,0 +1,71 @@
+from os import getcwd, path
+from typing import Callable
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+import time
+from .config import find_project_from_path, load_extras_config, load_tree_config
+from .build import compile_md_to_html
+from .log import warn
+from .errors import fatal
+
+def reload( file, tree_config, extras_config):
+ global current_url
+ try:
+ md_relpath = path.relpath(file, tree_config.markdown)
+ dest = path.join(tree_config.dest, md_relpath)
+ if dest.endswith(".md"):
+ dest = dest.removesuffix(".md") + ".html"
+ url = path.relpath(dest, tree_config.dest)
+ compile_md_to_html(file, dest, tree_config, extras_config)
+ return url
+ except Exception as e:
+ warn(str(e))
+
+def watch_files(tree_config, extra_config, reload_func:Callable | None=None):
+ last_reload = {}
+
+ class ReloadHandler(FileSystemEventHandler):
+ def on_modified(self, event):
+ reload_path = event.src_path
+ if event.is_directory :
+ if path.exists(path.join(event.src_path, "index.html")):
+ reload_path = path.join(event.src_path, "index.html")
+ else:
+ 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, tree_config, extra_config)
+ if reload_func: reload_func(file)
+
+
+
+ observer = Observer()
+ handler = ReloadHandler()
+ for file in [tree_config.markdown, tree_config.templates, tree_config.plugins, tree_config.static]:
+ observer.schedule(
+ handler,
+ path=file,
+ recursive=True
+ )
+ return observer
+
+def run_watcher(project_path):
+ try:
+ project_path = project_path if project_path else getcwd()
+ find_project_from_path(project_path)
+ extra_config = load_extras_config(project_path)
+ tree_config = load_tree_config(project_path)
+ observers = watch_files(tree_config, extra_config)
+ observers.start()
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ observers.stop()
+ observers.join()
+
+ except Exception as e:
+ fatal(e, f"Build failed: {e}")
diff --git a/src/webviewer.py b/src/webviewer.py
index e56877a..4c01068 100644
--- a/src/webviewer.py
+++ b/src/webviewer.py
@@ -9,9 +9,9 @@ import time
from .config import find_project_from_path, load_extras_config, load_tree_config, load_webview_config
from .errors import fatal, html_fatal
from .build import compile_md_to_html
-from .log import info
+from .watcher import watch_files
+from .log import die, info, warn
-current_url = ""
def http_server(host, port, routes):
class Handler(SimpleHTTPRequestHandler):
@@ -61,49 +61,12 @@ def http_server(host, port, routes):
server = HTTPServer((host, port), Handler)
return server
-def reload(window, file, tree_config, webview_config, extras_config):
- global current_url
+def reload_webview(window, url, webview_config):
try:
- md_relpath = path.relpath(file, tree_config.markdown)
- dest = path.join(tree_config.dest, md_relpath)
- if dest.endswith(".md"):
- dest = dest.removesuffix(".md") + ".html"
- current_url = path.relpath(dest, tree_config.dest)
- compile_md_to_html(file, dest, tree_config, extras_config)
- info(f"Reloading: {current_url}")
- if current_url:
- window.load_url(f"http://{webview_config.host}:{webview_config.port}/{current_url}")
+ window.load_url(f"http://{webview_config.host}:{webview_config.port}/{url}")
except Exception as e:
- window.load_url(f"data:text/html,{html_fatal(e, f'Failed to reload {file}')}")
-
-def watch_files(window, tree_config, webview_config, extras_config):
- last_reload = {}
- class ReloadHandler(FileSystemEventHandler):
- def on_modified(self, event):
- reload_path = event.src_path
- if event.is_directory :
- if path.exists(path.join(event.src_path, "index.html")):
- reload_path = path.join(event.src_path, "index.html")
- else:
- return
- now = time.time()
- last = last_reload.get(reload_path, 0)
- if now - last < 0.3:
- return
- last_reload[reload_path] = now
- reload(window, reload_path, tree_config, webview_config, extras_config)
-
-
- observer = Observer()
- handler = ReloadHandler()
- for file in [tree_config.markdown, tree_config.templates, tree_config.plugins, tree_config.static]:
- observer.schedule(
- handler,
- path=file,
- recursive=True
- )
- observer.start()
- return observer
+ window.load_url(f"data:text/html,{html_fatal(e, f'Failed to reload {url}')}")
+ warn(str(e))
def run(project_path):
try:
@@ -126,10 +89,15 @@ def run(project_path):
}
server = http_server(host, port, routes)
- Thread(target=server.serve_forever, daemon=True).start()
+ server_thread = Thread(target=server.serve_forever, daemon=True)
+ server_thread.start()
window = webview.create_window("Merodi", url=f"http://{host}:{port}/")
- observer = watch_files(window, tree_config, webview_config, extras_config)
+ observer = watch_files(
+ tree_config, extras_config,
+ lambda path: reload_webview(window, path, webview_config),
+ )
+ observer.start()
webview.start(debug=webview_config.dev_tools in ["true",1])
|