Rebuilt CLI watcher around new fswatch package#4026
Open
johnfav03 wants to merge 16 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request rebuilds tsgo --watch around the new internal/fswatch package (OS filesystem events + debouncing) instead of the previous polling loop, while keeping internal/vfs/vfswatch as a baseline-snapshot change detector for tracked compiler inputs.
Changes:
- Replaces the CLI watch loop with an event-driven fswatch subscription (recursive + ignore filter) and coalesced DoCycle signaling.
- Simplifies
internal/vfs/vfswatchby removing polling/timing/debounce machinery, leaving only snapshot + compare logic. - Introduces a new multi-backend
internal/fswatchimplementation (fanotify/inotify/kqueue/FSEvents/ReadDirectoryChangesW), plus extensive tests and documentation.
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/vfs/vfswatch/vfswatch.go | Removes polling-based watcher loop; keeps snapshot+compare watch-state logic. |
| internal/vfs/vfswatch/vfswatch_test.go | Updates tests for the new NewFileWatcher(fs) constructor. |
| internal/vfs/vfswatch/vfswatch_race_test.go | Updates race/fuzz tests to remove polling-interval related coverage. |
| internal/fswatch/windows.go | Adds Windows backend based on ReadDirectoryChangesW with overlapped I/O. |
| internal/fswatch/watcher.go | Adds core fswatch API surface, watcher lifecycle, per-dir state, and callback filtering. |
| internal/fswatch/walkdir.go | Adds generic walkDir implementation (portable baseline). |
| internal/fswatch/walkdir_windows.go | Adds Windows-optimized walkDir using FindFirstFile/FindNextFile. |
| internal/fswatch/walkdir_unix.go | Adds Unix walkDir using getdents/getdirentries for fewer stats. |
| internal/fswatch/walkdir_test.go | Adds tests validating walkDir behavior (symlinks, perms, entries, callbacks). |
| internal/fswatch/walkdir_other.go | Routes unsupported OSes to the generic walkDir implementation. |
| internal/fswatch/walkdir_dirent_noreclen.go | Adds DragonFlyBSD dirent helpers for reclen/inode extraction. |
| internal/fswatch/walkdir_dirent_linux.go | Adds Linux dirent helpers for reclen/inode extraction. |
| internal/fswatch/walkdir_dirent_fileno.go | Adds FreeBSD/OpenBSD/NetBSD dirent helpers for reclen/inode extraction. |
| internal/fswatch/walkdir_dirent_darwin.go | Adds macOS dirent helpers for reclen/inode extraction. |
| internal/fswatch/testutil_test.go | Adds retry-capable test harness to reduce platform flake impact. |
| internal/fswatch/README.md | Documents fswatch usage, watcher selection, and error semantics. |
| internal/fswatch/LICENSE | Adds upstream MIT license attribution. |
| internal/fswatch/kqueue.go | Adds kqueue backend for BSD/macOS (fd-per-entry model). |
| internal/fswatch/inotify_linux.go | Adds inotify backend for Linux. |
| internal/fswatch/fanotify_linux.go | Adds fanotify backend for Linux with rename probing/fallback. |
| internal/fswatch/fanotify_linux_test.go | Adds Linux fanotify-specific tests (availability, parsing, shutdown, cross-watcher). |
| internal/fswatch/fsevents_darwin.go | Adds macOS FSEvents backend (event classification and lifecycle). |
| internal/fswatch/fsevents_darwin_ffi.go | Adds cgo-free CoreFoundation/CoreServices/libdispatch FFI plumbing and NFC normalization helpers. |
| internal/fswatch/fsevents_darwin_ffi.s | Adds shared assembly trampolines and exported trampoline addresses. |
| internal/fswatch/fsevents_darwin_ffi_arm64.s | Adds arm64 FSEvents Create trampoline + callback shim assembly. |
| internal/fswatch/fsevents_darwin_ffi_amd64.s | Adds amd64 FSEvents Create trampoline + callback shim assembly. |
| internal/fswatch/fsevents_darwin_ffi_arm64_test.go | Adds static disassembly-based test ensuring the arm64 callback only touches safe registers. |
| internal/fswatch/fsevents_darwin_nfd_test.go | Adds macOS Unicode normalization regression tests (NFD/NFC mismatch scenarios). |
| internal/fswatch/event.go | Adds event kinds and per-path coalescing state machine. |
| internal/fswatch/eventlist_test.go | Adds unit tests for event coalescing and atomic drain semantics. |
| internal/fswatch/debounce.go | Adds per-backend debounce mechanism (min/max coalescing windows). |
| internal/fswatch/CHANGES.md | Documents divergence from upstream @parcel/watcher and lists bugfixes/features. |
| internal/fswatch/cgmanifest.json | Adds component governance manifest pointing at upstream source commit/tag. |
| internal/fswatch/canonicalize_other.go | Adds no-op path canonicalization for non-darwin platforms. |
| internal/fswatch/canonicalize_darwin.go | Adds NFC canonicalization for macOS path consistency. |
| internal/execute/watcher.go | Rebuilds CLI watcher to subscribe to fswatch events and signal DoCycle asynchronously. |
| .golangci.yml | Updates linter exclusion pattern to include internal/fswatch. |
jakebailey
reviewed
May 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The CLI watcher (
tsgo --watch) was previously implemented with a polling-based approach, using aRun()loop - the key disadvantage of this system is that I would still callStat()on tracked files even when they didn't change, which yielded an idle CPU usage of ~5% in thevscoderepo.With the addition of the
fswatchpackage (PR #3980), we can rebuild the watcher around OS-level filesystem events, which results in an idle CPU usage of <1% on average in thevscoderepo.fswatchbranch, so only commits from8230a72onward contain relevant changes.