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
#!/usr/bin/env bash
#
# Serve the docs locally with hot-reload. Binds the first free port in
# 8000-8030, so it never clashes with another project's docs server already
# running (common when working across repos). Pass your own `-a`/`--dev-addr`
# to override the auto-pick.
#
# Requires `zensical` — install with `pip install -r requirements.txt`
# in a venv, then re-run this script with that venv activated (or
# invoke ./.venv/bin/zensical directly).
#
# Common gotcha on Linux: Zensical's watcher consumes inotify
# instances. The kernel default (128 per user) runs out quickly on
# a dev machine with editors and file-syncers already open. If you
# see `Too many open files` / inotify panics, raise the cap:
#
# sudo sysctl fs.inotify.max_user_instances=512
#
# Persist it with:
#
# echo 'fs.inotify.max_user_instances=512' \
# | sudo tee /etc/sysctl.d/99-inotify.conf
# sudo sysctl --system
#
# Preflight: Zensical's watcher fails at inotify_init1 if the user's
# cap (fs.inotify.max_user_instances) is saturated by other running
# processes — typically VS Code, file syncers, etc. Count what's
# actually held and compare to the sysctl cap.
limit=
held=
if ; then
fi
# Non-fatal: getting close to the cap — warn but proceed.
if ; then
fi
# Pick the first free port in 8000-8030 so concurrent docs servers (one per
# repo) don't fight over 8000 — unless the caller passed their own address.
PORT_MIN=8000
PORT_MAX=8030
addr_given=0
for; do
done
# True when something is already LISTENING on $1, on ANY address and either
# IP family. zensical binds `localhost`, which often resolves to IPv6 `::1`,
# so an IPv4-only connect probe misses it - use `ss` (Linux), then `lsof`
# (macOS/BSD), then a best-effort connect probe.
if ; then
chosen=""
for; do
if ! ; then
chosen=""
break
fi
done
if ; then
else
fi
fi