watch
ergonomic file-watching (over the fs primitive)
use watchThe ergonomic layer of filesystem observation, over the tier 0 primitive
fs.watch_raw(the thin wrapper ofinotify/kqueue/FSEvents/ReadDirectoryChangesW, which lives in the core, being a syscall and mechanism). The compiler/LSP uses the primitive directly (tier 0 does not depend on tier 1); whoever wants convenience (debounce, recursion, normalization across OSes, ignore-globs) imports this lib. Coherent with signals-as-channel: events arrive on aChannel, not on a global callback.
The primitive (in the core fs, tier 0): reference
Section titled “The primitive (in the core fs, tier 0): reference”// lives in `fs` (tier 0); listed here only for context:fn fs.watch_raw(path: string) -> Result[Channel[->RawFsEvent], error{NotFound, Io}]decl RawFsEvent { pub path: string; pub kind: RawKind }decl RawKind { Created; Modified; Deleted; MovedFrom; MovedTo } // raw, as the OS reportsThe lib (tier 1): normalized and coalesced events
Section titled “The lib (tier 1): normalized and coalesced events”fn watch(path: string) -> Result[Watcher, error{NotFound, Io}] // one pathfn watch_tree(root: string) -> Result[Watcher, error{NotFound, Io}] // recursive
decl Watcher { pub events: Channel[->FsEvent] }fn (w: *Watcher) with_debounce(d: Duration) -> Watcher // coalesces bursts (a save fires N raw events)fn (w: *Watcher) ignore(glob: string) -> Watcher // ignores paths (node_modules, .git)fn (w: *Watcher) close() // closes the channel / ends the observation
decl FsEvent { Created(string) Modified(string) Deleted(string) Renamed(from: string, to: string) // rename-tracking: joins the OS's MovedFrom+MovedTo into a single event}use watch
w := watch.watch_tree("src").or_panic().with_debounce(200ms).ignore("**/.git/**")loop ev in w.events { match ev { Modified(p) => rebuild(p) Renamed(from, to) => { drop(from); rebuild(to) } Created(p) => rebuild(p) Deleted(p) => drop(p) }}Curation
Section titled “Curation”- Primitive in the core, service in tier 1: the same split as
runtime(thetraceprimitive is core, the observer is tooling) and asMemorySource(syscall core, strategy lib). The part the compiler/LSP needs (fs.watch_raw) is tier 0; only the convenience is tier 1, and the dependency rule holds. - Events as channel (
signals-as-channel, §4): no global callback; cancelling is closing the channel or killing the process. - The lib normalizes what the OS makes messy: burst debounce, coalesced recursion, rename-tracking (joins the OS’s two move half-events), ignore-globs. Policy that churns stays in tier 1, not in the core.