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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//! Generic rebuild-worker driver for dev servers.
//!
//! Spawns a background OS thread that owns the rebuild loop:
//! 1. Block waiting for a tick.
//! 2. Drain any extra ticks queued before the thread woke up — they
//! coalesce into a single rebuild.
//! 3. Run the user-supplied rebuild closure.
//! 4. Drain any ticks that arrived during the rebuild — if any did,
//! re-tick ourselves so the next iteration runs without waiting.
//! 5. Report success / error via [`RebuildReporter`] and broadcast
//! the corresponding live-reload event.
//!
//! The closure is the only thing that varies between consumers
//! (webui-cli builds and renders an app, webui-press rebuilds a docs
//! site). It returns `Result<Vec<String>, RebuildError>`: the `Ok` value is a
//! list of plain advisory lines to print under the rebuild line, and the `Err`
//! lets the worker print a terminal rendering and broadcast a plain one to
//! browsers.
use PathBuf;
use ;
use thread;
use crateLiveReload;
use crateRebuildReporter;
/// Tick-channel capacity. Bounded so a watcher event burst can't
/// unboundedly queue inside the rebuild worker. The worker drains all
/// pending ticks before each build, so a dropped `try_send` on a full
/// channel coalesces the same way the drain loop does.
const TICK_CHANNEL_CAPACITY: usize = 8;
/// Tick sender given to the watcher closure. Cheap to clone.
///
/// Each tick carries the changed paths from one debounce window, so the worker
/// can name the file(s) that triggered the rebuild. Send an empty `Vec` to
/// force a rebuild with no attributed trigger.
pub type TickSender = ;
/// Failure returned by a rebuild closure.
///
/// Carries two renderings of the same error so the worker can route each to
/// the surface that needs it:
///
/// - `display` — text for the terminal [`RebuildReporter`]. May embed ANSI
/// color, but each line must keep its **own** self-contained SGR span:
/// a single span that straddles newlines bleeds when the line is later
/// re-prefixed (e.g. `[server]` under `xtask dev`).
/// - `message` — plain, color-free text broadcast to connected browsers over
/// live-reload (logged to the dev console / shown in overlays). Never embed
/// ANSI here — browsers render escape codes as literal garbage.
///
/// Use [`RebuildError::plain`] (or the `From<String>` / `From<&str>`
/// conversions) when one rendering serves both surfaces.
/// Spawn the rebuild worker on a dedicated OS thread and return the
/// sender used to enqueue rebuild ticks. The watcher closure should
/// call `tx.try_send(paths)` with the changed paths for every filesystem
/// event burst — failed sends (channel full) are intentional coalescing.
///
/// The closure runs synchronously on the worker thread, so it may use
/// blocking I/O freely. It returns `Ok(warnings)` on success (a possibly-empty
/// list of plain, color-free advisory lines to print under the rebuild line) or
/// `Err(RebuildError)` on failure; the worker prints the error's terminal
/// rendering and broadcasts its plain message to connected browsers.
///
/// The returned [`TickSender`] does not need to be held to keep the
/// worker alive — the worker stops only when every clone of the
/// sender is dropped.