Skip to content

Live folder watching for the file picker (v0.1.6) - #8

Merged
dsaad68 merged 3 commits into
mainfrom
improvements
Jul 7, 2026
Merged

Live folder watching for the file picker (v0.1.6)#8
dsaad68 merged 3 commits into
mainfrom
improvements

Conversation

@dsaad68

@dsaad68 dsaad68 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • The file picker, "New tab" picker, and project search no longer go stale when markdown files are added/removed/renamed in the watched directory — a new FolderWatcher (macOS FSEvents) flags changes the same way Terminal.didResize already flags a resize, and the picker re-scans and refreshes live while open.
  • Fixes two issues caught in review before release: TerminalMenu.run() is now mutating so a live refresh persists across picker re-entries (it previously reverted the moment run() returned), and FSEvents teardown was moved out of the SIGINT/SIGTERM handler (not async-signal-safe, and unnecessary since _exit already tears the process down).
  • Bumps appVersion to 0.1.6 and adds a CHANGELOG entry.

Test plan

  • swift build — macOS
  • swift test — 259/259 passing
  • swiftformat --lint / swiftlint lint --strict clean on changed files
  • Manual verification in tmux: added/removed files appear live in the picker with no keypress; list persists correctly after opening a file and returning to the picker; Ctrl-C still exits cleanly

🤖 Generated with Claude Code

dsaad68 and others added 3 commits July 6, 2026 12:31
termdown only scanned its target directory once at startup, so the file
picker, "New tab" picker, and project search all went stale until the app
was restarted. Add a macOS FSEvents watcher (FolderWatcher) that flags a
change the same way SIGWINCH already flags a resize (Terminal.folderChanged),
and have the picker re-scan and refresh entries/details/LiveGrep's cache
live while it's open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…down

Code review of the previous commit caught two real bugs:

- TerminalMenu.run() was non-mutating, so a folder-change refresh only
  updated a local shadow of items/details that was discarded when run()
  returned. Since main.swift reuses the same `menu` value for the whole
  session, any live refresh was silently reverted the next time the picker
  opened (e.g. after viewing a file and returning to it). Making run()
  mutating lets it write back to self directly, so the caller's `menu`
  keeps the refreshed list across calls.

- FolderWatcher.stop() (FSEventStreamStop/Invalidate) was called from the
  SIGINT/SIGTERM handler, which isn't async-signal-safe and risked a
  deadlock on Ctrl-C if a CF/dispatch lock was held at signal time. It's
  also unnecessary there: that path calls _exit(0) immediately, so the
  whole process (and its FSEvents queue/fd) is torn down by the OS
  regardless. Only the atexit path (graceful quit) still calls it, since
  that's the one with cleanup that has an effect outliving the process
  (restoring the terminal).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dsaad68
dsaad68 merged commit 500c613 into main Jul 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant