Repository navigation
How Folder Watching Works
Nibtree notices changes on its own: an edit in another editor, a commit in the terminal, a new repository after git clone. One file watcher per workspace folder sorts every file event into "this repository changed" or "the folder changed". The rest of the workspace is in How workspaces work.
- No refresh button hunting. Changes, the Files panel, the Log and the branch names should follow what happens on disk.
- No polling. Asking git for every status every few seconds costs CPU and memory in big workspaces. The operating system's file events are free until something changes.
- Only the right repository refreshes. In a folder with fifty repositories, an edit in one must not reread the other forty-nine.
watcher::watch puts one debounced (300 ms) recursive watcher on a folder, plus the .git of an enclosing repository outside it and the git folders that linked worktrees and absorbed submodules point to. Each batch goes through the pure function attribute:
flowchart TD
E["File event path"] --> G{"A .git entry created,<br/>removed or renamed?"}
G -->|yes| WR["workspace-changed<br/>with reposChanged"]
G -->|no| R{"Inside a known repo?<br/>(deepest wins)"}
R -->|"no, and not inside a .git"| W["workspace-changed"]
R -->|"no, a new HEAD in an unknown .git"| WR
R -->|yes| D{"Inside that repo's .git?"}
D -->|yes| N{"objects, logs, lfs or *.lock?"}
N -->|yes| X["Dropped"]
N -->|no| RG["repo-changed, gitDir"]
D -->|no| I{"Ignored by .gitignore<br/>and not tracked?"}
I -->|"yes, open in a tab"| OF["open-files-changed"]
I -->|"yes, not open"| X
I -->|no| RW["repo-changed, workTree<br/>plus workspace-changed"]
Other paths inside an unknown .git are dropped. Removing or moving a folder that holds a known repository, or moving in a folder with a .git (has_git_entry), also sets reposChanged. A changed submodule also refreshes its parent repository (with_submodule_parents), since the parent's status shows it. Batches that add, remove or rename files mark the Go to File index stale, and edits to source files mark the symbol index, so search stays current (see How Search Everywhere works).
A path counts as ignored only when a .gitignore rule matches it and it is not tracked (IgnoreCheck): git still follows a tracked file that a rule matches, so its status and diffs must too. The index is read once per batch, and only when a path matched a rule.
An ignored file has no status, so nothing told its tab that it changed: an open log file showed only what it had when it opened. The page sends the files open in any tab (preview tabs too) with watch_open_files, whenever that list changes. OpenFiles (open_files.rs) keeps them per window, by real path. An ignored path that is open is not dropped: the batch reports it, and the watcher sends open-files-changed with the paths as the page named them. The store bumps openFileVersions[filePath], and FileView reloads that tab like any other change from outside.
A reload replaces only the part that changed (editor/reloadChange.ts), so the caret and scroll stay. When the view is scrolled to the end and the text grew there, it scrolls to the new end, so a growing log is followed.
In the store, repo-changed calls refreshRepo. workspace-changed reloads the Files panel, and with reposChanged the store runs a quiet rescan one second later (RESCAN_DELAY_MS). That changes nothing unless the list of repositories changed; then it rewatches, refreshes and shows "Found repository NAME" (or "Found N new repositories"). Scan for Repositories (rediscover) still works too.
watch_workspace and unwatch_workspace are async commands. They build and drop watchers through commands::blocking, because a Tauri command without async runs on the main thread, and dropping a watcher waits for its threads. Watchers live in AppState.watchers, keyed by folder root.
The watcher type is Debouncer<RecommendedWatcher, NoCache> (state.rs). The default file id cache walks every file under the folder when watching starts and keeps all their paths in memory. It is only needed to pair renames, and the watcher only asks which repository changed.
| File | What it does |
|---|---|
src-tauri/src/watcher.rs |
watch, attribute, IgnoreCheck, has_git_entry, linked git folders, submodule parents |
src-tauri/src/open_files.rs |
OpenFiles: the files open in each window's tabs |
src-tauri/src/state.rs |
RepoWatcher (with NoCache) and the watchers map |
src-tauri/src/commands/workspace.rs |
watch_workspace, unwatch_workspace, stop_watcher
|
src/lib/stores/repo.svelte.ts |
watchAll, refreshRepo, scheduleRescan, rescan, openFilePaths, openFileVersions
|
src/lib/views/workspaceLife.svelte.ts |
sends openFilePaths to watch_open_files when it changes |
src/lib/editor/reloadChange.ts |
the smallest edit from the text on screen to the text on disk |
Sort events in a pure function. attribute takes paths and two small lookups, so every case is tested without a real watcher.
Drop git's noise. Objects, logs, LFS files and lock files change on every git command and never change what the UI shows.
Rescan only on a hint. A rescan of a big folder is costly, so it runs only when a .git appeared, vanished or moved, once the burst settles.
No file id cache. Pairing renames is not worth a walk of every file and a copy of every path in memory.
Report only open ignored files. Sending every ignored path would flood the page during a build or npm install. The open tabs are the only ignored files anyone looks at, and the list is a few paths.
The watching bugs and their fixes are in Folder Watching Bugs We Fixed. The freeze when watching a big folder started is in How workspaces work.
-
src-tauri/src/watcher.rs:attributecases (noise, ignored paths, ignored files open in a tab, an enclosing repository,reposChangedfor new, removed and moved repositories), the search index hints, linked git folders, submodule parents,IgnoreCheckwith a tracked ignored file, andhas_git_entryon a real folder. -
src-tauri/src/open_files.rs: open files kept by real path per window, also a file that does not exist yet. -
src/lib/editor/reloadChange.test.ts: appended lines, a changed middle, emptied, truncated and repeated text.
Live watchers need a check by hand with scripts/make-workspace-demo.sh. See Testing.
- Update this page when
attribute, the events or the watcher setup change. - Events are listed in Commands and Events.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode